MODULE Cat;

(*==============================================================*
 * Modul:               CAT-Hauptmodul                          *
 * Autor:               Johannes G”ttker-Schnetmann, Dirk Steins*
 * erstellt am:         Mai 1990                                *
 * letzte Žnderung am:  30.11.1993                              *
 * Version:             2.52                                    *
 * Interne Version:     V#0075                                  *
 *==============================================================*

 Ich habe eben beim Durchsehen noch einige alte Konventionen gefunden, mal
 sehen, da muž ich noch einiges moderniseren, damit "data" nicht wieder
 ein Pfusch wird. Wahrscheinlich werde ich auch die interne Nummerierung
 der Gruppen umstellen, d.h. private = 0, alles andere ab 1 aufsteigend,
 das scheint mir zukunftssicher.

 Žchtung: Jetzt kann es wegen der Nummerierung von 'private' #
 'privateMessages' noch Probleme geben!

 Unter anderem sind die Array's Gruppe und SpezGr samt Initialisierung
 jetzt rausgeflogen, allerdings zeigt die Gruppenbox jetzt die Anzahl der
 neuen noch nicht richtig an, das muž auch noch behoben werden.

 Weitere Kompromisse f�r den šbergang:
 1. bzgl. data/MTDatabase-šbergang
 - data.InitDatabase(), data.readPos() und data.writePos() liefern Ergebnis,
   das auf den M�ll geworfen wird
 - KillTo, KillOneGroup nicht verf�gbar, ausgeklammert
 - SetNewState gibt's auch noch nicht

 2. bzgl grin/MTVDIAnzeige
 - StartPos Nummer/Datum noch nicht implementiert
 - Marken setzen nicht m”glich (alternate-Zahl)
 - "conversion ", "stichWort", "FromName" .. :-))) Das war nat�rlich v”lliger
   Pfusch
 - ShowVDIHeader gibt's noch nicht
 - IsHeaderWinTop
 - FontSelect HeaderFont (gibt's nat�rlich noch garnicht)
 - PrintMessage/SaveMessage
 - NewOut (Streichen?), ResetInternalState, SearchMenuSelected,
   QuoteBlock, WriteInfoLine, DoSearch, GetActualUser, CheckInfoLine, "msgHandle"

 *----------------------------------------------------------------------------
 * Datum    Vers. Autor  Žnderung (Arbeitsbericht)
 *----------------------------------------------------------------------------
 * ??? Mitte 1990 bis Dezember 1991 diverses..
 * 22.12.91       JGS    rudiment„re Anpassung an neues Datenbankmodul "data"
 *                       und Anzeige "grin"
 * 25.02.92       JGS    Anpassung der letzten diffs an mein 'neues' Hauptmodul
 *                       unter Ber�cksichtigung der neuen Datenbank/Anzeige
 * 07.03.92 -
 * 09.03.92 0003  JGS    Diverse Anpassungen, u.a. MTEdit2 soweit wie m”glich
 *                       entfernt, besserer Programmstart, schnellere Hauptschleife
 * 22.03.92       JGS    Parser eingebaut
 * 01.04.92       JGS    Einige Kleinigkeiten angepažt, u.a. InvertStatus
 * 02.04.92       JGS    Status bei pers”nlichen Msgs
 *----------------------------------------------------------------------------
 *)

(* F�r Fehlerbehandlung unter der Shell: *)
FROM PrgCtrl            IMPORT CatchProcessTerm, TermCarrier;
FROM MOSGlobals         IMPORT MemArea;

FROM MathLib0           IMPORT pi, cos, sin, int;
IMPORT MathLib0, FileNames;
FROM SysUtil2           IMPORT SetJump, LongJump, JumpBuf;

FROM SYSTEM             IMPORT ADDRESS, ADR, CODE, CADR, ASSEMBLER, TSIZE, CALLSYS, BYTE;
IMPORT BinOps;
FROM Storage            IMPORT ALLOCATE, DEALLOCATE, AllAvail;
FROM Characters         IMPORT CR, LF;
FROM SwapServer         IMPORT SplitWordToByte, SmallerCard, SmallerInt;
FROM Messages           IMPORT NewMessage, NewPersMsg;
FROM MsgInfile          IMPORT MakeInFile;
FROM Infofiles          IMPORT LoadInfoInf;
FROM InfoDlg            IMPORT doInfoList;
FROM MTPaths            IMPORT ARCPath, MessagePath, ImportPath,
                               ExportPath, DataPath, TerminalPath, ARCName,
                               archiveName, TerminalName, enarcStr,
                               dearcStr, TerminalCmd, ReadInf, lastInfName;
FROM MTEdit2            IMPORT OpenEditWindow;
IMPORT CatEdit;
FROM UserInformation    IMPORT UserBLK, ReadUserBlock, 
                               batchProcess;
FROM VDIUtil            IMPORT FormHandle;
FROM VDIStandards       IMPORT SetState, SetSpec, SetFlags, GetSpec,
                               GetState, InitVDIStandards,
                               SelectFont, StatusEnable, 
                               enableMenuItems, enableNewTop, CheckItem;
FROM CatFiles           IMPORT OpenFile, openMode, ReadFile, CloseFile,
                               ClearPath, DeleteFile, SetPath, Seek,
                               WriteMuch, SeekMode, WriteFile, ErrorAlert,
                               FileSize;
FROM Void               IMPORT v;
FROM ZSearchDial        IMPORT InitMenuStr, FlagDial, DialAction, DialActionSet;
FROM ConvertDate        IMPORT DateOk;
FROM Protokoll          IMPORT IsProtokoll, React, SendTerminate, SendHelp, 
                               SendProgstart, ProtoInit, SendAcknowledge,
                               CatReadMsgInfo, SendExtendedHelp,
                               SendPrintFile;
FROM CatButtons         IMPORT DisplayButton, CloseButton, ClickIsInButton,
                               InitButtonWindow, DrawButton, IsButtonTop,
                               buttonWindowLocked;


FROM SearchMenu         IMPORT MenuSearch;
IMPORT ShellCall;
IMPORT GruppenAuswahl;

(* MM2-Module *)
IMPORT StrConv;         (* wird eh von MagicConvert importiert *)
IMPORT Block;           (* Wird auch vom Editor benutzt *)

(* ListBox *)
IMPORT Lists;
IMPORT Strings;

IMPORT MTE;
IMPORT MausTauschrsc;

(* MagicLib *)
IMPORT MagicAES;
IMPORT MagicVDI;
IMPORT MagicDOS;
IMPORT MagicXBIOS;
IMPORT MagicStrings;
IMPORT MagicConvert;
IMPORT MagicSys;
IMPORT MagicCookie;

(* MagicTools *)
IMPORT mtAppl;
IMPORT mtCommand;
IMPORT mtUtils;
IMPORT mtDials;
IMPORT mtDir;
IMPORT mtAlerts;
IMPORT mtPopups;
IMPORT mtTextfiles;
IMPORT mtRsc;
IMPORT mtAESMenus;

(* Mint-Module *)
IMPORT MintUtil;
IMPORT Mintbind;

(* CAT-Module *)
FROM CatGlobal  IMPORT magIx, magIxVer, multiGEM, multiTOS, multiTask, minTos14, 
                       saveAllPositions, isMintDomain;
IMPORT CatFiles;
IMPORT FontSelect;
IMPORT WdwManager;
IMPORT ConfVars;
IMPORT Printer;

IMPORT data;
IMPORT dataSys;
IMPORT grin;
IMPORT Parser;
IMPORT CatTypes;
IMPORT CatGlobal;
IMPORT Clip;
IMPORT ListHelp;
IMPORT grinTools;
IMPORT ConvertDate;
IMPORT msgList;                         (* Neues Stichwortlistenmodul *)
IMPORT Messages;                        (* Base-Routinen f�r neue Nachrichten  *)
IMPORT MsgWindow;                       (* Windowhandling f�r neue Nachrichten  *)
IMPORT Varnames;                        (* Variablennamen f�r CFG-Variablen *)
IMPORT CatHelp;                         (* Einfache Hilfestellung in Dialogbox *)
IMPORT CatButtons;                      (* Das ButtonWindow-Module *)
IMPORT treeList;                        (* Graphische Kommentarb„ume *)
IMPORT ZCalcCrc;
IMPORT CatOpts;
IMPORT CatOpts2;
IMPORT CatUtil;
IMPORT GroupSelect;
IMPORT WinDials;
IMPORT DoITK;
IMPORT WiederVorlage;


CONST   
        magicPCCookie = 'MgPC';

CONST   sysStrOne       = 'Shell aufrufen';

        (* Anzeigestrings f�r Loadbox *)
        cInitInf    = "Lese CAT.INF";
        cInitConfig = "Lese Konfigurationsdatei";
        cInitGrin   = "Initialisiere Anzeigemodul";
        cInitGroups = "Initialisiere Gruppenliste";
        cInitData   = "Initialisiere Datenbank";
        cInitPrint  = "Lese Druckerkonfiguration";
        cInitMsgMan = "Initialisiere Nachrichtenmanager";
        cInitInfos  = "Initialisiere Infodateien";
        cInitList   = "Initialisiere Stichwortlistenmodul";
        cInitNames  = "Sortiere Namensliste";
        cInitButton = "Initialisiere Funktionsfenster";
        cInitRsc    = "Initialisiere Resource";
        cInitClip   = "Initialisiere Clipboard";
        cInitDials  = "Initialisiere Gruppendialoge";

     CFGName    = 'printer.cfg';
     allWild    = '*.*';

TYPE String     = ARRAY[0..79] OF CHAR;
     StringPtr  = POINTER TO String;

VAR menu,
    desk,
    gruppen,
    wegen,
    about,
    adr,
    groups,
    system      : ADDRESS;
    BMess       : BOOLEAN;
    neoDeskBugFix: BOOLEAN;
    mayUseHidden : BOOLEAN;

VAR L         : LONGCARD;
    j,t, win  : INTEGER;

    moX, moY  : INTEGER;
    moButton  : BITSET;
    kReturn   : INTEGER;
    moKState  : BITSET;
    bReturn   : INTEGER;
    lastEvent,
    event     : BITSET;
    e         : BITSET;
    mess,
    mScrap    : ARRAY[0..7] OF INTEGER;
    scan,
    char      : CHAR;
    dr, mrect : RECORD
                  CASE :BOOLEAN OF
                    TRUE : x,y,w,h : INTEGER|
                    FALSE: adr, dum: ADDRESS
                  END
                END;
    null      : RECORD d1,d2 : LONGCARD END;
    startTerm : BOOLEAN;
    termStarted : BOOLEAN;
    mouse     : BOOLEAN;
    dontSwitchOffMouse : BOOLEAN;   (* Nur nicht die Maus ausschalten *)
    EndOfPrg  : BOOLEAN;
    fastExit  : BOOLEAN;
    lastApId  : INTEGER;
    chPid,
    termPid   : INTEGER;
    shell     : ShellCall.shellType;

    ButtonWindowOpen : BOOLEAN;
    conState         : CARDINAL;
    
    catDTA           : MagicDOS.DTA;
    
    filterNumber     : INTEGER;
    catCheckJumpBuf  : JumpBuf;


VAR (* F�r die FlagBox *)
    setBits, clearBits : BITSET;
    lastAction         : DialAction;

(* Kleiner Stack f�r Keyboard-Events *)
CONST   maxKeys = 16;
TYPE    kbdEvent    = RECORD
                        kstate : BITSET;
                        scan   : CHAR;
                        ch     : CHAR;
                      END;
VAR keyStack    : ARRAY [0..maxKeys-1] OF kbdEvent;
    keyWrite    : INTEGER;
    keyRead     : INTEGER;

PROCEDURE PopKey (VAR ks: BITSET; VAR sc : CHAR; VAR c : CHAR);
BEGIN
  IF keyRead # keyWrite THEN
    WITH keyStack[keyRead] DO
      ks   := kstate;
      sc   := scan;
      c    := ch;
    END;
    keyRead := (keyRead + 1) MOD maxKeys;
  END;
END PopKey;

PROCEDURE PushKey (ks: BITSET; sc, c : CHAR);
BEGIN
  WITH keyStack[keyWrite] DO
    kstate := ks;
    scan   := sc;
    ch     := c;
  END;
  keyWrite := (keyWrite + 1) MOD maxKeys;
  IF keyWrite = keyRead THEN 
    (* hat keyRead eingeholt, einmal rum! 
     * keyRead auf n„chsten setzen 
     *)
    keyRead := (keyWrite + 1) MOD maxKeys;
  END;
END PushKey;

PROCEDURE PendingKey (): BOOLEAN;
BEGIN
  RETURN keyRead # keyWrite;
END PendingKey;

PROCEDURE InitRsc():BOOLEAN;
VAR z         : CARDINAL;
    bp        : CARDINAL;

    (* Ein paar Baumadressen, die hier nur tempor„r gebraucht werden *)
    colPopup  : ADDRESS;
    verStr    : ARRAY [0..20] OF CHAR;

BEGIN
  menu      := MausTauschrsc.TreeAddr^[MausTauschrsc.menu];
  desk      := MausTauschrsc.TreeAddr^[MausTauschrsc.desk];
  gruppen   := MausTauschrsc.TreeAddr^[MausTauschrsc.gruppen];
  wegen     := MausTauschrsc.TreeAddr^[MausTauschrsc.wegen];
  about     := MausTauschrsc.TreeAddr^[MausTauschrsc.about];
  adr       := MausTauschrsc.TreeAddr^[MausTauschrsc.adr];
  groups    := MausTauschrsc.TreeAddr^[MausTauschrsc.groups];
  system    := MausTauschrsc.TreeAddr^[MausTauschrsc.system];
  colPopup  := MausTauschrsc.TreeAddr^[MausTauschrsc.colpopup];

  IF ~InitMenuStr()             THEN RETURN FALSE END;

  shell := ShellCall.IsShell();
  IF shell = ShellCall.noShell THEN SetState(menu, MausTauschrsc.callshel, {MagicAES.DISABLED}) END;
  
  SetSpec(about, MausTauschrsc.date, CADR(CatTypes.CatDate));
  SetSpec(about, MausTauschrsc.date, CADR(CatTypes.CatDate));
  SetSpec(about, MausTauschrsc.version, CADR(CatTypes.CatVersion));
  
  MagicStrings.Assign ("CAT " + CatTypes.CatVersion, verStr);
  mtUtils.SetObjcString (MausTauschrsc.TreeAddr^[MausTauschrsc.cat_icon], MausTauschrsc.the_icon, verStr);
  
  mtUtils.SetObjcString (adr,     MausTauschrsc.newadr,"");
  mtUtils.SetObjcString (gruppen, MausTauschrsc.newgroup,"");
  mtUtils.SetObjcString (MausTauschrsc.TreeAddr^[MausTauschrsc.whichnr], MausTauschrsc.nrstring,"");
  mtUtils.SetObjcString (MausTauschrsc.TreeAddr^[MausTauschrsc.datumein], MausTauschrsc.ddate,"");
  mtUtils.SetObjcString (MausTauschrsc.TreeAddr^[MausTauschrsc.findbox], MausTauschrsc.ssuchstr,"");
  mtUtils.SetObjcString (MausTauschrsc.TreeAddr^[MausTauschrsc.system],  MausTauschrsc.sysstr,"");
  
  IF mtAppl.Bitplanes < 4 
  THEN
    CatOpts.maxColors := 1;
    FOR z := 1 TO CARDINAL(mtAppl.Bitplanes) DO
      CatOpts.maxColors := CatOpts.maxColors * 2;
    END;
    bp := CatOpts.maxColors * 2;
    FOR z := bp+1 TO 32 DO
      mtUtils.ExclFlag (colPopup, z, MagicAES.SELECTABLE);
      mtUtils.InclState (colPopup, z, MagicAES.DISABLED);
    END;
  ELSE
    CatOpts.maxColors := 16;
  END;

  RETURN TRUE;
END InitRsc;

PROCEDURE DoAbout;
VAR j : INTEGER;
BEGIN
  j := FormHandle(about);
  IF j = MausTauschrsc.ainfo THEN 
    CatHelp.DoHelp (CatHelp.catinfo);
  END;
END DoAbout;

PROCEDURE ClearScreen();
BEGIN
  MagicDOS.Cconout(33C); MagicDOS.Cconout('E');
END ClearScreen;

PROCEDURE ClearBuffer(e : BITSET; force : BOOLEAN; ks: BITSET; sc: INTEGER; char: CHAR);
  VAR kstate : BITSET;
      scanCh : CHAR;
      scan   : INTEGER;
      ch     : CHAR;
      kReturn: INTEGER;
BEGIN
  IF MagicAES.MUKEYBD IN e THEN
    (* Parameter-Array f�llen *)
    MagicAES.AESIntIn[0] := INTEGER({MagicAES.MUKEYBD, MagicAES.MUTIMER});

    MagicAES.AESIntIn[14] := 0;   (* ev_mtlocount: 0 ms *)
    MagicAES.AESIntIn[15] := 0;   (* ev_mthicount: 0 *)
    
    MagicAES.AESAddrIn[0] := ADR(mess);
    
    REPEAT
      e := MagicAES.EvntPmulti ();
      kstate := MagicSys.CastToBitset(MagicAES.AESIntOut[4]);
      kReturn  := MagicAES.AESIntOut[5];
      SplitWordToByte(kReturn, scanCh, ch);
      scan := ORD (scanCh);
    UNTIL ~(MagicAES.MUKEYBD IN e) (* OR ((CAP(char) IN CatTypes.charSet{'A'..'Z','0'..'9'}) & (sc < 54)) *)
        OR (~force & ((ks#kstate) OR (scan # sc)));
    IF MagicAES.MUKEYBD IN e
    THEN
      PushKey (kstate, CHR(scan), ch);
    END;
  END;
END ClearBuffer;

PROCEDURE ProcessFilter (wdw: INTEGER; withDial: BOOLEAN);
  VAR cmd       : CatTypes.String255;
BEGIN
  IF (withDial & CatOpts2.doFilter (filterNumber, cmd)) OR
     (~withDial & CatOpts2.doPopupFilter (filterNumber, cmd))
  THEN
    IF filterNumber <= 7
    THEN
      CASE filterNumber OF
        0   : CatEdit.BlockRot  (wdw); |
        1   : CatEdit.BlockRot18 (wdw); |
        2   : CatEdit.BlockSwap (wdw); |
        3   : CatEdit.BlockUp   (wdw); |
        4   : CatEdit.BlockDown (wdw); |
        5   : CatEdit.BlockCapitals (wdw); |
        6   : CatEdit.BlockMirror (wdw); |
        7   : CatEdit.BlockDecode (wdw); |
      ELSE
      END;
    ELSE
      IF LENGTH(cmd) > 0
      THEN
        CatUtil.PipeEditBlock (wdw, cmd);
      END;
    END;
  END;
END ProcessFilter;

PROCEDURE DoShell();
VAR shellCommand : CatTypes.String255;
    j : INTEGER;
BEGIN
  mtUtils.SetObjcStringAdr(system, MausTauschrsc.systitle, CADR(sysStrOne));
  mtUtils.ObjcString(system, MausTauschrsc.sysstr, shellCommand);
  IF FormHandle(system) # MausTauschrsc.sysabruc THEN
    mtUtils.ObjcString(system, MausTauschrsc.sysstr, shellCommand);
    IF ~multiTask
    THEN
      mtAppl.MouseOff;
      ClearScreen();
      v.bool := data.WritePos();
      MagicAES.WindUpdate(MagicAES.ENDUPDATE);
    END;
    ShellCall.CallShell (shellCommand, FALSE);
    IF ~multiTask
    THEN
      MagicAES.WindUpdate (MagicAES.BEGUPDATE);
    END;
    v.bool := data.ReadPos();
    IF ~multiTask
    THEN
      MagicDOS.Cconws(CR+CR+'- Taste dr�cken -');
      ClearBuffer({MagicAES.MUKEYBD}, TRUE, {}, 0, 0C);
      MagicAES.EvntKeybd(v.int, v.int, v.char);
      MagicDOS.Cconws(33C+'f'+0C);        (* Cursor ausschalten *)
      mtAppl.MouseArrow;
      MagicAES.FormDial(MagicAES.FMDFINISH, null, WdwManager.deskSize);
      v.int := MagicAES.MenuBar(menu, MagicAES.Set);
    END;
  ELSE
    mtUtils.SetObjcString(system, MausTauschrsc.sysstr, shellCommand);
  END;
END DoShell;

PROCEDURE ReadInfoDatei(doFsel: BOOLEAN; groupsDeleted: BOOLEAN);FORWARD;

PROCEDURE ButtonHandler(x,y: INTEGER; Button: BITSET; Clicks: INTEGER; kstate : BITSET; obj : INTEGER);
CONST   wgStr   = 'Wegen:';
VAR z : CARDINAL;
    Gruppe  : CatTypes.String255;
    Betreff : CatTypes.String255;
    str     : CatTypes.String255;
    ca      : CARDINAL;
    c       : CHAR;
    start   : CARDINAL;

  PROCEDURE Wiggle(obj : INTEGER; simple: BOOLEAN);
  BEGIN
    SetState(desk, obj, {MagicAES.SELECTED});
    DrawButton(obj);
    IF ~CatGlobal.tos3DLook & ~simple
    THEN
      MagicAES.EvntTimer(75);
      SetState(desk, obj, {});
      DrawButton(obj);
      MagicAES.EvntTimer(75);
      SetState(desk, obj, {MagicAES.SELECTED});
      DrawButton(obj);
    END;
  END Wiggle;

  PROCEDURE Normal(obj : INTEGER);
  BEGIN
    SetState(desk, obj, {});
    DrawButton(obj);
  END Normal;

  PROCEDURE ChangeIt();
  BEGIN
    IF BMess THEN
      Wiggle (MausTauschrsc.messages, FALSE);
      SetState(desk, MausTauschrsc.stichwor, {});
      SetState(desk, MausTauschrsc.messages, {MagicAES.SELECTED})
    ELSE
      Wiggle (MausTauschrsc.stichwor, FALSE);
      SetState(desk, MausTauschrsc.messages, {});
      SetState(desk, MausTauschrsc.stichwor, {MagicAES.SELECTED});
    END;
    DrawButton(MausTauschrsc.stichwor);
    DrawButton(MausTauschrsc.messages);
    CheckItem (menu, MausTauschrsc.treadmsg, ~BMess);
  END ChangeIt;

  PROCEDURE HandlePers(item : INTEGER);
  BEGIN
    MagicStrings.Assign ('', str);
    IF ListHelp.SelectName(str) THEN
      IF grinTools.BetreffHolen (-1, Betreff, 'Stichwort f�r neue pers”nliche Nachricht an:',
                                 str, wgStr, FALSE) THEN
        Normal(item);
        NewPersMsg(str, "", Betreff);
      ELSE
        Normal(item);
      END
    ELSE
      Normal(item);
    END
  END HandlePers;

(*TYPE getNumberProc = PROCEDURE ((* dataHandle *) ADDRESS):CARDINAL;*)
  PROCEDURE getIdNumber(ptr : data.OneGroupHandle):CARDINAL;
  BEGIN
    RETURN data.NumberOfID(ptr, str);
  END getIdNumber;

  PROCEDURE getDateNumber(ptr : data.OneGroupHandle):CARDINAL;
  BEGIN
    RETURN data.NumberOfDate(ptr, ConvertDate.StrToDate(str));
  END getDateNumber;

VAR mode : grin.openMode;
    sMode: ListHelp.groupSelectMode;

BEGIN
  Betreff := "";
  Gruppe  := "";
  IF obj = -1 THEN
    IF ClickIsInButton(x,y) THEN
      obj := MagicAES.ObjcFind(desk, 0, 99, x, y)
    ELSE
      RETURN
    END;
  END;
  CASE obj OF
    MausTauschrsc.newmess   :
      Wiggle(MausTauschrsc.newmess, FALSE);
      (* HandlePublic *)
      ListHelp.SetLastGroup (Gruppe);
      IF ~ListHelp.SelectGroup(Gruppe, ca, TRUE, FALSE, FALSE, ListHelp.gsmWrite) THEN
        Normal(MausTauschrsc.newmess);
        RETURN
      END;
      IF ca # dataSys.private THEN
        IF Gruppe[0] = "" THEN MagicStrings.Assign ('™ffentlich', Gruppe) END;
        IF grinTools.BetreffHolen (-1, Betreff, 'Stichwort f�r neue Mitteilung in Gruppe:',
                                   Gruppe, wgStr, FALSE) THEN
          Normal(MausTauschrsc.newmess);
          NewMessage(Gruppe, Betreff);
        ELSE
          Normal(MausTauschrsc.newmess);
        END
        ELSE
        HandlePers(MausTauschrsc.newmess)
      END |
    MausTauschrsc.newpers:
      Wiggle(MausTauschrsc.newpers, FALSE);
      HandlePers(MausTauschrsc.newpers) |
    MausTauschrsc.readpos,
    MausTauschrsc.readall,
    MausTauschrsc.readnew,
    MausTauschrsc.readnum,
    MausTauschrsc.readdate,
    MausTauschrsc.readunread:
      Wiggle(obj, FALSE);
      (* Lesemodus bestimmen *)
      CASE obj OF
        MausTauschrsc.readpos : sMode := ListHelp.gsmReadLastPos; |
        MausTauschrsc.readall : sMode := ListHelp.gsmReadBegin;   |
        MausTauschrsc.readnew : sMode := ListHelp.gsmReadNew;     |
        MausTauschrsc.readnum : sMode := ListHelp.gsmReadId;      |
        MausTauschrsc.readdate    : sMode := ListHelp.gsmReadDate; |
        MausTauschrsc.readunread  : sMode := ListHelp.gsmReadUnread; |
      ELSE
        sMode := ListHelp.gsmOther;
      END;
  
      IF ListHelp.SelectGroup(Gruppe, ca, FALSE, FALSE, FALSE, sMode) THEN
        IF obj = MausTauschrsc.readnum THEN
          IF CatOpts2.NrHolen(str) THEN 
            IF BMess THEN
              v.int := grin.grinOpenWithProc(ca, getIdNumber, grin.grinNextMess, 0, grin.mOther)
            ELSE
              msgList.listOpenWithProc (ca, getIdNumber, -1, grin.mOther);
            END;
          END;
          Normal(obj); RETURN
        ELSIF obj = MausTauschrsc.readdate THEN
          IF CatOpts2.DatumHolen(FALSE, str) THEN
            IF BMess
            THEN
              v.int := grin.grinOpenWithProc(ca, getDateNumber, grin.grinNextMess, 0, grin.mOther)
            ELSE
              msgList.listOpenWithProc (ca, getDateNumber, -1, grin.mOther);
            END;
          END;
          Normal(obj); RETURN
        END;
        CASE obj OF
          MausTauschrsc.readpos: 
            start := data.lastReadMsgOfGroup(ca); 
            mode := grin.mLastPos; |
          MausTauschrsc.readall: 
            start := 0; 
            mode := grin.mFromBeginning; |
          MausTauschrsc.readnew: 
            start := data.FirstNewMsg(ca); 
            mode := grin.mFirstNew; |
          MausTauschrsc.readunread:
            start := data.unreadMsgPos(ca);  
            mode := grin.mUnread; |
        ELSE
        END;
        Normal(obj);
        IF BMess THEN
          v.int := grin.grinOpenMessage(ca, start, grin.grinNextMess, 0, mode)
        ELSE
          msgList.listOpen (ca, start, -1, mode)
        END;
      ELSE
        Normal(obj);
      END; |
    MausTauschrsc.stichwor,
    MausTauschrsc.messages:
      IF BMess # (obj = MausTauschrsc.messages)
      THEN  
        BMess := (obj = MausTauschrsc.messages); 
        ChangeIt();
        v.bool := ConfVars.SetConfigBool (cReadMess, BMess);
      END |
    MausTauschrsc.catinfna,
    MausTauschrsc.catinfn0,
    MausTauschrsc.catinfn1:
      obj := MausTauschrsc.catinfna;
      Wiggle (obj, TRUE);
      ReadInfoDatei (TRUE, FALSE);
      Normal (obj); |
  ELSE
  END;
END ButtonHandler;

VAR lbox: ADDRESS;
    lbsr,
    lbr : mtUtils.tRect;
    
PROCEDURE InitLoadingBox (REF s: ARRAY OF CHAR): BOOLEAN;
BEGIN
  lbox := MausTauschrsc.TreeAddr^[MausTauschrsc.loadbox];
  mtUtils.SetObjcString (lbox, MausTauschrsc.lver, CatTypes.CatVersion);
  MagicAES.FormCenter (lbox, lbr);
  lbsr := mtUtils.tRect {0,0,10,10};
  MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  MagicAES.FormDial (MagicAES.FMDSTART, lbsr, lbr);
  MagicAES.FormDial (MagicAES.FMDGROW, lbsr, lbr);
  mtUtils.SetObjcString (lbox, MausTauschrsc.inittext, s);
  MagicAES.ObjcDraw (lbox, 0, 8, lbr);
  RETURN TRUE;
END InitLoadingBox;

PROCEDURE TellLoadingBox (REF s: ARRAY OF CHAR): BOOLEAN;
  VAR r : mtUtils.tRect;
BEGIN
  mtUtils.SetObjcString (lbox, MausTauschrsc.inittext, s);
  mtUtils.CalcArea (lbox, MausTauschrsc.inittext, r);
  MagicAES.ObjcDraw (lbox, 0, 8, r);
  RETURN TRUE;
END TellLoadingBox;

PROCEDURE FreeLoadingBox ();
BEGIN
  MagicAES.FormDial (MagicAES.FMDSHRINK, lbsr, lbr);
  MagicAES.FormDial (MagicAES.FMDFINISH, lbsr, lbr);
  MagicAES.WindUpdate (MagicAES.ENDUPDATE);
END FreeLoadingBox;

PROCEDURE ReadInfoDatei(doFsel: BOOLEAN; groupsDeleted: BOOLEAN);
VAR z : CARDINAL; scrap : ARRAY[0..15] OF CHAR;
    ap : ARRAY[0..1] OF CHAR;
    str: CatTypes.String255;
    cfgFile : CatTypes.String255;
BEGIN
  mtDir.SplitPath (CatGlobal.infName, str, str, scrap);
  IF scrap[0] # ''
  THEN
    ap := '*.';
    MagicStrings.Insert(ap, scrap, 0);
  ELSE
    scrap := '*.inf'
  END;

  IF ~doFsel OR CatGlobal.FselGet(CatGlobal.infPath, CatGlobal.infName, scrap, 'Infodatei laden', FALSE) THEN
    CloseButton(FALSE);
    grin.grinCloseAll();
    msgList.listCloseAll();
    msgList.listFreeAll();
    treeList.treeCloseAll();
    IF ~WdwManager.CloseAllWindows (FALSE) THEN RETURN END;
    v.bool := data.WritePos();       (* Positionstabelle zur�ckschreiben *)
    IF ~groupsDeleted
    THEN
      v.bool := GroupSelect.SaveChangedGroupList (); (* Gruppenliste zur�ckschreiben, falls ge„ndert *)
    END;
    v.bool := InitLoadingBox(cInitInf);
    IF ReadInf(CatGlobal.infPath, CatGlobal.infName, TRUE, TRUE) THEN
      (* Hier auch noch die Namenslisten und Gruppenlisten freigeben! *)
      ConfVars.DeleteAllVars();
      ConfVars.CloseConfig();
      v.bool := TellLoadingBox (cInitConfig);
      ReadUserBlock();
      CatGlobal.SetColors();
      v.bool := TellLoadingBox (cInitGrin);
      v.bool := grin.grinInit();
      v.bool := TellLoadingBox (cInitGroups);
      v.bool := GroupSelect.ReadGroupList(); (* Muž eigentlich beachtet werden! *)
      v.bool := WiederVorlage.ReadResubList();
      v.bool := TellLoadingBox (cInitData);
      v.bool := data.InitDataBase();
      IF ConfVars.GetConfigString (cPrtCfg, cfgFile)
      THEN
        v.bool := TellLoadingBox (cInitPrint);
        Printer.LoadCFGFile (cfgFile);
      END;
      v.bool := TellLoadingBox (cInitMsgMan);
      MsgWindow.InitMessageManager();
      ConfVars.GetConfDefBool (cReadMess, BMess, TRUE);
      mtUtils.SetState(desk, MausTauschrsc.stichwor, MagicAES.SELECTED, ~BMess);
      mtUtils.SetState(desk, MausTauschrsc.messages, MagicAES.SELECTED, BMess);
      CheckItem (menu, MausTauschrsc.treadmsg, ~BMess);
      ButtonWindowOpen := DisplayButton(TRUE);
      v.bool := TellLoadingBox (cInitInfos);
      LoadInfoInf(TRUE, FALSE);
      v.bool := TellLoadingBox (cInitList);
      IF ConfVars.GetConfigBool(cSortNames,v.bool) & v.bool
      THEN
        v.bool := TellLoadingBox (cInitNames);
        data.SortList (data.names);
      END;
      ConfVars.GetConfDefStr (cPrivateLine, str, CatTypes.cPrivateDefault);
      msgList.SetListLine(str, TRUE);
      ConfVars.GetConfDefStr (cGlobalLine, str, CatTypes.cGlobalDefault);
      msgList.SetListLine(str, FALSE);
      ConfVars.GetConfDefBool (cHiddenFeatures, mayUseHidden, FALSE);
      WiederVorlage.CheckForResub ();
    END;
    FreeLoadingBox ();
  END;
  mtAppl.MouseBusy();
  mtAppl.MouseArrow();
END ReadInfoDatei;


PROCEDURE StartPrg(REF Path : ARRAY OF CHAR; Name, cmd : ARRAY OF CHAR; BWin :BOOLEAN;
                   doParallel: BOOLEAN):INTEGER;
VAR res  : INTEGER;
    ptail: CatTypes.String255;
    ap   : ARRAY[0..1] OF CHAR;
    prev : INTEGER;
    w   : RECORD handle,d1,d2,d3 : INTEGER END;

  PROCEDURE isAppl():BOOLEAN;
  BEGIN
    RETURN TRUE;
  END isAppl;

  PROCEDURE KillWinds();
  BEGIN
    prev := 0;
    LOOP
      MagicAES.WindGet(0, MagicAES.WFTOP, w);
      (* Ende, wenn das Desktop-Fenster erreicht wurde oder *)
      (* wenn ein Fenster nicht geschlossen werden konnte   *)
      IF (w.handle = 0) OR (w.handle = prev) THEN EXIT END;
      MagicAES.WindClose(w.handle);
      MagicAES.WindDelete(w.handle);
      IF WdwManager.IsInQueue (w.handle)
      THEN
        WdwManager.WindowIsClosed (w.handle);
      END;
      prev := w.handle;
    END;
    ConfVars.GetConfDefBool (cClearBackground, v.bool, TRUE);
    IF minTos14 & v.bool THEN
      MagicAES.WindNew(); (* wind_update ist schon *)
      MagicAES.WindUpdate(MagicAES.BEGUPDATE);  (* WindUpdate kurz wieder anschalten *)
    END
  END KillWinds;

BEGIN
  IF ~multiTask OR
     multiGEM OR
     ~doParallel
  THEN
    
    (* Alle eigenen Fenster schliežen *)
    IF ~CatUtil.WriteSavePos(FALSE, TRUE) THEN RETURN 0 END;
    
    IF BWin THEN
      CloseButton(FALSE)
    END;
    
    (* Watchdog Bescheid geben *)
    SendTerminate(FALSE);
    
    v.int := MagicAES.MenuBar(menu, MagicAES.Reset);
  
    (* L„nge der Kommandozeile in Byte Nummer 0 *)
    IF cmd[0] # ''
    THEN
      ap := ' ';
      MagicStrings.Insert(ap, cmd, 0);
      cmd[0] := CHR(MagicStrings.Length(cmd));
    END;

    v.bool := SetPath(Path);
  
    MagicStrings.Assign(Path, ptail);
    MagicStrings.Append(Name, ptail);
    IF minTos14 & ~neoDeskBugFix & ~multiTOS
    THEN
      (* Shellwrite ausf�hren *)
      chPid := MagicAES.ShelWrite(1,1,1, ptail, cmd); (* Richtig! Etwas merkw�rdige Bezeichnung *)
    END;
    IF MagicAES.AESGlobal.apCount = 1 THEN (* kein MultiTOS/MultiGEM *)
      (* hier demn„chst noch die Men�zeile ersetzen *)
      MagicAES.ApplExit(); (* AC_CLOSE an ACCs senden *)
      mtAppl.ApplIdent := MagicAES.ApplInit();
      (* Eigentlich soll man darauf nur lesend zugreifen, aber diese Ausnahme ist wohl erlaubt *)
      KillWinds();
    END;
  
    MagicAES.ApplExit();
  
    IF SetPath(Path) THEN
      (* Zur Sicherheit die Positionstabelle speichern *)
      v.bool := data.WritePos();
      v.bool := GroupSelect.SaveChangedGroupList (); (* Gruppenliste zur�ckschreiben, falls ge„ndert *)
      ap[0] := 0C; (* Leeres Environment, MagicDOS setzt dann einen Nullpointer ein *)
      MagicAES.WindUpdate(MagicAES.ENDUPDATE);
      res := MagicDOS.Pexec(MagicDOS.LoadnGo, Name, cmd, ap);
      MagicAES.WindUpdate(MagicAES.BEGUPDATE);
      IF MagicAES.AESGlobal.apCount = 1 THEN KillWinds(); END;
      v.bool := data.ReadPos();
      mtAppl.MouseArrow;
    END;
  
    mtAppl.ApplIdent := MagicAES.ApplInit();
  
    MagicAES.FormDial(MagicAES.FMDFINISH, null, WdwManager.deskSize);
    IF BWin & ButtonWindowOpen THEN
      ButtonWindowOpen := DisplayButton(FALSE);
    ELSE
      ButtonWindowOpen := FALSE;
    END;
    
    (* tempor„ren Pfad holen bevor Konfigbereich gewechselt wird! *)
    CatUtil.GetPosPath (ptail);
    Strings.Append (CatUtil.tmpInf, ptail, v.bool);
    (* Konfigbereich wechseln *)
    ConfVars.ConfigConfigModule (TRUE);
    IF ConfVars.ReadConfigFile (ptail)
    THEN
      (* Alles wieder restaurieren *)
      MsgWindow.msgRestorePos();
      grin.grinRestorePos();
      msgList.listRestorePos();
      CatEdit.EditRestorePos();
      CatGlobal.ApplPath (ptail);
      v.bool := DeleteFile (ptail, CatUtil.tmpInf);
    END;
    (* Variablen wieder l”schen *)
    ConfVars.DeleteAllVars();
    (* Und wieder auf normale Einstellung *)
    ConfVars.ConfigConfigModule (FALSE);
    CatGlobal.SetColors();
    
    WdwManager.HandlePendingEvents();
    
    v.int := MagicAES.MenuBar(menu, MagicAES.Set);
    mtAppl.MouseArrow();
  ELSE
    (* Mag!X oder MultiTOS *)
    (* L„nge der Kommandozeile in Byte Nummer 0 *)
    ap := ' ';
    MagicStrings.Insert(ap, cmd, 0);
    cmd[0] := CHR(MagicStrings.Length(cmd));

    IF SetPath(Path) THEN END;
  
    MagicStrings.Assign(Path, ptail);
    MagicStrings.Append(Name, ptail);
    MagicAES.WindUpdate(MagicAES.ENDUPDATE);
    IF multiTOS & ~magIx
    THEN
      (* AES >= 4.0, parallel starten *)
      chPid := MagicAES.ShelWrite(0,1,1, ptail, cmd); 
    ELSE
      (* Mag!X, parallel starten *)
      chPid := MagicAES.ShelWrite(1,1,100, ptail, cmd); 
    END;
    IF chPid = 0 THEN res := -1 ELSE res := 0 END;
    MagicAES.WindUpdate(MagicAES.BEGUPDATE);
  END;
  RETURN res
END StartPrg;

PROCEDURE StartIt();
CONST loadInfAlt = '[2][CAT:|Aktuelle Info laden?][[Ja|:[Nein]';
VAR i : INTEGER;
    startStr : CatTypes.pathStrType;
    scrapStr : CatTypes.nameStrType;
BEGIN
  IF CatGlobal.FselGet(CatGlobal.prgPath, CatGlobal.prgName, '*.prg', 'Programm starten', FALSE) THEN
  
    startStr := '';
    
    i := StartPrg(CatGlobal.prgPath, CatGlobal.prgName, startStr, TRUE, TRUE);
    IF (i = 04711H) &
       (mtAlerts.Alert(1, loadInfAlt) = 1) OR
       (i = 04712H) THEN
      ReadInfoDatei(TRUE, FALSE);
    ELSIF (i = 04713H) THEN
      (* Return from CatPutz *)
      ReadInfoDatei (FALSE, TRUE);
    ELSIF (i # 0)
    THEN
      ErrorAlert (i);
    END;
  END;
END StartIt;

PROCEDURE CallInfo();
VAR res : INTEGER;
    ext : ARRAY [0..12] OF CHAR;
    path,
    name,
    callStr : ARRAY[0..255] OF CHAR;

BEGIN
  IF doInfoList (TRUE, callStr)
  THEN
    mtDir.SplitPath (callStr, path, name, ext);
    OpenEditWindow (path, name, FALSE, UserBLK.infoRO);
  END;
END CallInfo;

PROCEDURE CreateInfile(): BOOLEAN;
BEGIN
  Messages.MsgAskForSave();
  IF MakeInFile()
  THEN
    Messages.ReloadEditors();
    RETURN TRUE;
  END;
  RETURN FALSE;
END CreateInfile;

PROCEDURE DecodeOutfile();
  VAR val : BOOLEAN;
      logName : ARRAY [0..14] OF CHAR;
BEGIN
  grin.grinCloseAll();
  msgList.listCloseAll();
  treeList.treeCloseAll();
  msgList.listFreeAll();
  IF Parser.OutfileEinsortieren() (* ConvertOutfile() *) THEN
    v.bool :=GroupSelect.SaveChangedGroupList();
    IF ~batchProcess & UserBLK.MakeAfterDecode THEN 
      v.bool := CreateInfile() 
    END;
    IF ConfVars.GetConfigBool (cShowLog, val)
       & val
       & ~batchProcess
    THEN
      logName := 'LOG.txt';
      OpenEditWindow (DataPath, logName, FALSE, UserBLK.infoRO);
    END;
  END;
END DecodeOutfile;

PROCEDURE StartTerminal(inBatch: BOOLEAN);
  VAR res : INTEGER;
BEGIN
  IF ~batchProcess & UserBLK.MakeBeforeTerminal THEN 
    IF ~CreateInfile() THEN RETURN END;
  END;
  IF UserBLK.TermAsOverlay
  THEN
    IF saveAllPositions
    THEN
      EndOfPrg := CatUtil.WriteSavePos (FALSE, FALSE)
    ELSE
      grin.grinCloseAll();      (* Die grin-Fenster m�ssen unbedingt vor denen 
                                 * von msgList geschlossen werden
                                 *)
      msgList.listCloseAll();
      treeList.treeCloseAll();
      msgList.listFreeAll();
      CloseButton (TRUE);
      EndOfPrg := WdwManager.CloseAllWindows (FALSE);
    END;
    IF ~EndOfPrg THEN RETURN END;
    startTerm := TRUE;
    RETURN
  END;
  res := StartPrg (TerminalPath, TerminalName, TerminalCmd, TRUE, ~inBatch);
  IF res < 0 THEN ErrorAlert (res); END;
  termPid := chPid;
  IF (res = 0) & (multiTOS OR magIx)
  THEN
    termStarted := ~inBatch;
  ELSE
    termStarted := FALSE;
  END;
  IF ~batchProcess & 
    (~(multiTOS OR magIx) OR inBatch) &
     (res = 0)
  THEN
    (* Bei MultiTOS auf Event CHEXIT warten *)
    IF UserBLK.DecodeAfterRun THEN DecodeOutfile() END;
  END;
END StartTerminal;

PROCEDURE QuoteBlock (wdw : INTEGER; withShift: BOOLEAN); 

  PROCEDURE GetInitials(botWdw : INTEGER; VAR str : ARRAY OF CHAR);
  VAR z, zz, l : CARDINAL;
      from     : ARRAY [0..255] OF CHAR;
  
  PROCEDURE putChar();
  BEGIN
    IF (zz <= l) & ~(from[zz] IN CatTypes.charSet{' ','@','"',"'",'(',')'}) & (z < HIGH (str)) THEN
      str[z] := CAP(from[zz]);
      INC(z);
    END;
  END putChar;
  
  BEGIN
    z := 0;
    IF UserBLK.initialQuote THEN
      grin.ActualName (botWdw, from);
      l := MagicStrings.Length(from);
      IF l > 0 THEN
        zz := 0;
        DEC(l);
        REPEAT
        
          (* Immer noch nicht sch”n, aber besser als vorher *)
          WHILE (zz <= l) & (from[zz] IN CatTypes.charSet{' ','_','-','"','(',')'}) DO INC(zz) END;
          IF (zz = 0) OR ((zz > 0) & ~(from[zz-1] IN CatTypes.charSet{"<",'"',"'","("}))
          THEN
            putChar();
          END;
          WHILE (zz <= l) & ~(from[zz] IN CatTypes.charSet{' ','_','-','@'}) DO INC(zz) END;
        UNTIL (zz>=l) OR (from[zz] = '@') OR (z>= HIGH(str));
      END;
    END;
    str[z] := '>';
    str[z+1] := 0C;
  END GetInitials;
  
  VAR botWdw : INTEGER;
      buf    : ADDRESS;
      bufLen : LONGCARD;
      pre    : ARRAY [0..7] OF CHAR;
BEGIN
  (* Erstmal falsche Fenster abfangen *)
  IF grin.grinWindowTop (wdw) OR ~CatEdit.IsEditTop (wdw) THEN RETURN END;

  (* Kein zweites Fenster offen? *)
  IF ~WdwManager.GetSecondWdw (botWdw) THEN RETURN END;

  (* Das untere Fenster ist kein MessageWindow? Geht nicht! *)
  IF ~grin.grinWindowTop (botWdw) THEN 

    (* Pr�fen, ob nur ein MessageWindow offen ist *)
    IF ~grin.grinOnlyOneWind (botWdw)
    THEN
      RETURN 
    END;
  END;
  (* Kein Block markiert? Zur�ck! *)
  IF ~CatEdit.BlockIsMarked (botWdw) THEN RETURN END;
  IF ~CatEdit.GetBlock (botWdw, FALSE, withShift, buf, bufLen) THEN RETURN END;
  (* Jetzt noch Initialien holen *)
  GetInitials (botWdw, pre);
  (* Test, ob Block zu grož *)
  IF bufLen >= MAX(CARDINAL)
  THEN
    MTE.info (MTE.longQuote);
    DEALLOCATE (buf, 0);
  ELSE
    (* Und jetzt Block einsetzen *)
    v.bool := CatEdit.QuoteSomething (wdw, pre, buf, SHORT(bufLen), 75);
  END;
  DEALLOCATE (buf, 0);
END QuoteBlock;

PROCEDURE ExternalPrint (wdw: INTEGER): BOOLEAN;
  VAR path, name: CatTypes.String255;
      printed: BOOLEAN;
      cmdLine,
      ideaParm,
      ideaPath,
      ideaName : CatTypes.String255;
BEGIN
  (* tempor„re Datei erstellen *)
  CatUtil.makeTmpName (path, name);
  (* Text in Datei schreiben *)
  CatEdit.EditSave(wdw, path, name, FALSE);
  (* Jetzt externes Druckprogramm aufrufen *)
  printed := SendPrintFile (path, name, CatEdit.GetMode (wdw, CatEdit.effMode));

  (* Wenn nicht �ber Protokoll gedruckt, dann Idealist starten 
   * mit Kommandozeile 
   *)
  IF ~printed
  THEN
    IF ConfVars.GetConfigString (cIdealist, ideaPath)
    THEN
      FileNames.SplitPath (ideaPath, ideaPath, ideaName);
      MagicStrings.Assign ("-BDE", cmdLine);
      IF CatEdit.GetMode (wdw, CatEdit.effMode)
      THEN
        MagicStrings.Append ("+", cmdLine);
      ELSE
        MagicStrings.Append ("-", cmdLine);
      END;
      IF ConfVars.GetConfigString (cIdealistParm, ideaParm)
      THEN
        MagicStrings.Append (" ", cmdLine);
        MagicStrings.Append (ideaParm, cmdLine);
      END;
      MagicStrings.Append (" ", cmdLine);
      MagicStrings.Append (path, cmdLine);
      MagicStrings.Append (name, cmdLine);
      printed := StartPrg (ideaPath, ideaName, cmdLine, TRUE, TRUE) >= 0;
    END;
  END;
  IF ~printed
  THEN
    (* tempor„re Datei wieder l”schen *)
    v.bool := CatFiles.DeleteFile (path, name);
  END;
  RETURN printed;
END ExternalPrint;

PROCEDURE doHelp (wdw : INTEGER; kstate : BITSET);
VAR buf    : POINTER TO ARRAY [0..$7FFF] OF CHAR;
    bufLen : LONGCARD;
    str    : CatTypes.String127;
    txt    : CatTypes.String127;
BEGIN
  IF CatGlobal.WithShift (kstate)
  THEN
    str := 'CAT - Das MausTausch-FrontEnd';
    txt := 'cat.hyp';
    IF ~mouse THEN
      mtAppl.MouseOn; mouse := TRUE;
    END;
    IF CatEdit.IsEditTop (wdw) & CatEdit.BlockIsMarked (wdw) 
    THEN
      IF CatEdit.GetBlock (wdw, FALSE, FALSE, buf, bufLen) THEN 
        SendHelp (buf^);
        DEALLOCATE (buf, 0);
      ELSE
        v.bool := SendExtendedHelp (str, txt);
      END;
    ELSE
      v.bool := SendExtendedHelp (str, txt);
    END;
    dontSwitchOffMouse := TRUE;
  ELSE
    IF grin.grinWindowTop (wdw)
    THEN
      CatHelp.DoHelp (CatHelp.grin);
    ELSIF CatEdit.IsEditTop (wdw) 
    THEN
      CatHelp.DoHelp (CatHelp.editor);
    ELSIF MsgWindow.msgWindowTop (wdw) 
    THEN
      CatHelp.DoHelp (CatHelp.manager);
    ELSIF msgList.listWindowTop (wdw)
    THEN
      CatHelp.DoHelp (CatHelp.msglist);
    ELSIF treeList.treeWindowTop (wdw)
    THEN
      CatHelp.DoHelp (CatHelp.treelist);
    ELSE
      CatHelp.DoHelp (CatHelp.general);
    END;
  END;
END doHelp;

PROCEDURE WriteInfoline (wdw : INTEGER; kstate: BITSET);
  VAR botWdw : INTEGER;
BEGIN
  (* Erstmal falsche Fenster abfangen *)
  IF grin.grinWindowTop (wdw) OR ~CatEdit.IsEditTop (wdw) THEN RETURN END;
  (* Kein zweites Fenster offen? *)
  IF ~WdwManager.GetSecondWdw (botWdw) THEN RETURN END;
  (* Das untere Fenster ist kein MessageWindow? Geht nicht! *)
  IF ~grin.grinWindowTop (botWdw) THEN 
    (* Pr�fen, ob nur ein MessageWindow offen ist *)
    IF ~grin.grinOnlyOneWind (botWdw)
    THEN
      RETURN 
    END;
  END;
  (* Erstmal noch Infozeile �berpr�fen *)
  IF CatGlobal.WithShift (kstate) 
  THEN
    IF ~CatOpts.CheckInfoline(UserBLK.infoline2) THEN RETURN END;
    (* Und jetzt Zeile basteln und in Editor *)
    grin.grinInfoline (botWdw, wdw, UserBLK.infoline2);
  ELSE
    IF ~CatOpts.CheckInfoline(UserBLK.infoline1) THEN RETURN END;
    (* Und jetzt Zeile basteln und in Editor *)
    grin.grinInfoline (botWdw, wdw, UserBLK.infoline1);
  END;
END WriteInfoline;

VAR InPath : CatTypes.pathStrType;
    InSel  : CatTypes.nameStrType;
    
    openPath : CatTypes.pathStrType;
    openSel  : CatTypes.nameStrType;

PROCEDURE MenuMessageHandler(item, title : CARDINAL; kstate : BITSET);
CONST quitAlt = '[2][CAT:|CAT wirklich beenden?][[Ja|:[Nein]';
      makeInAlt = '[2][CAT:|Infile erstellen?][[Ja|:[Nein]';
      insOutAlt = '[2][CAT:|Outfile einf�gen?][[Ja|:[Nein]';
      saveCnfAlt = '[2][CAT:|Konfiguration|speichern?][[Ja|:[Nein]';
      
VAR res    : INTEGER;
    z, z2  : CARDINAL;
    message: ARRAY[0..40] OF CHAR;
    wild   : ARRAY[0..6] OF CHAR;
    fInfo  : FontSelect.tFontinfo;
    hdl    : INTEGER;
    font,
    size   : INTEGER;
    actSet : DialActionSet;
    ownTopWdw: INTEGER;

  PROCEDURE handleFSelMessage (item : CARDINAL);
  BEGIN
    wild := allWild;
    IF item = MausTauschrsc.editfile THEN message := 'Datei laden'; 
    ELSIF item = MausTauschrsc.tmerge THEN message := 'Datei hinzuladen'; 
    END;

    IF CatGlobal.FselGet(openPath, openSel, wild, message, FALSE) THEN
      IF (item = MausTauschrsc.editmess)
      OR (item = MausTauschrsc.editfile) 
      THEN
        OpenEditWindow(openPath, openSel, FALSE, FALSE);
      ELSIF item = MausTauschrsc.tmerge THEN
        CatEdit.EditMerge(ownTopWdw, openPath, openSel);
      END
    END
  END handleFSelMessage;

BEGIN
  IF ~ mouse THEN mtAppl.MouseOn; mouse := TRUE; END;
    WdwManager.GetOwnTopWindow (ownTopWdw);
    CASE item OF
      MausTauschrsc.tabout : DoAbout() |
      (* Datei-Menu *)
      MausTauschrsc.editfile,
      MausTauschrsc.tmerge  : handleFSelMessage (item) |
      MausTauschrsc.editmess: MsgWindow.msgOpen(TRUE); |
      MausTauschrsc.tclose  : IF ~WdwManager.WindowIsIcon (WdwManager.theTopWindow)
                              THEN
                                v.bool := WdwManager.CloseWindow (WdwManager.theTopWindow, FALSE);
                              END; |
      MausTauschrsc.tsave   : IF CatEdit.IsEditTop(ownTopWdw) THEN
                                CatEdit.EditSave(ownTopWdw, '', '', FALSE)
                              END; |
      MausTauschrsc.saveas  : IF msgList.listWindowTop (ownTopWdw)
                              THEN
                                msgList.listSaveAs (ownTopWdw);
                              ELSE
                                IF CatEdit.IsEditTop (ownTopWdw) &
                                   CatEdit.BlockIsMarked (ownTopWdw)
                                THEN
                                  MagicStrings.Assign ('Block sichern als', message);
                                ELSE
                                  MagicStrings.Assign ('Sichern als', message);
                                END;
                                IF CatGlobal.FselGet(CatGlobal.SavePath, CatGlobal.SaveName, allWild, message, FALSE) THEN
                                  IF CatEdit.IsEditTop(ownTopWdw) THEN
                                    CatEdit.EditSave(ownTopWdw, CatGlobal.SavePath, CatGlobal.SaveName, TRUE)
                                  END;
                                END;
                              END; |
      MausTauschrsc.tprint  : IF CatEdit.IsEditTop(ownTopWdw) THEN
                                IF ConfVars.GetConfigBool (cExternalPrint, v.bool) & v.bool
                                THEN
                                  IF ~ExternalPrint (ownTopWdw)
                                  THEN
                                    CatEdit.EditPrint (ownTopWdw, CatEdit.BlockIsMarked (ownTopWdw));
                                  END;
                                ELSE
                                  CatEdit.EditPrint (ownTopWdw, CatEdit.BlockIsMarked (ownTopWdw));
                                END;
                              END |
      MausTauschrsc.mstartit: StartIt() |
      MausTauschrsc.callshel: DoShell() |
      MausTauschrsc.mausinfo: CallInfo() |
      MausTauschrsc.loadinf : ReadInfoDatei(TRUE, FALSE) |
      MausTauschrsc.tquit   : IF UserBLK.security & (mtAlerts.Alert(1, quitAlt) = 1) OR
                                ~UserBLK.security
                              THEN
                                 IF saveAllPositions
                                 THEN
                                   EndOfPrg := CatUtil.WriteSavePos (FALSE, TRUE);
                                 ELSE
                                   grin.grinCloseAll();
                                   msgList.listCloseAll();
                                   treeList.treeCloseAll();
                                   msgList.listFreeAll();
                                   CloseButton (TRUE);
                                   EndOfPrg := WdwManager.CloseAllWindows (FALSE);
                                 END;
                                 IF EndOfPrg THEN RETURN END;
                              END; |

      (* Bearbeiten-Menu *)
      MausTauschrsc.tundo   : IF CatEdit.IsEditTop (ownTopWdw)
                              THEN 
                                CatEdit.DoUndo (ownTopWdw); 
                              END; |
      MausTauschrsc.tcut    : IF ~CatGlobal.WithShift (kstate) THEN Clip.ScrapClear('',''); END;
                              v.bool := CatEdit.EditCut(ownTopWdw) |
      MausTauschrsc.tcopy   : IF CatEdit.IsEditTop(ownTopWdw) THEN
                                IF ~CatGlobal.WithShift (kstate) THEN Clip.ScrapClear('',''); END;
                                v.bool := CatEdit.EditCopy(ownTopWdw);
                              ELSIF msgList.listWindowTop (ownTopWdw)
                              THEN
                                msgList.listCopy (ownTopWdw)
                              END; |
      MausTauschrsc.tpaste  : CatEdit.EditPaste (ownTopWdw) |
      MausTauschrsc.tselall : IF CatEdit.IsEditTop (ownTopWdw)
                              THEN
                                CatEdit.MarkAll (ownTopWdw);
                              ELSIF msgList.listWindowTop (ownTopWdw)
                              THEN
                                msgList.listSelectAll (ownTopWdw, TRUE);
                              ELSIF treeList.treeWindowTop (ownTopWdw)
                              THEN
                                treeList.treeSelectAll (ownTopWdw);
                              ELSIF MsgWindow.msgWindowTop (ownTopWdw)
                              THEN
                                MsgWindow.msgSelectAll (ownTopWdw);
                              END;|
      MausTauschrsc.blockrot: ProcessFilter (ownTopWdw, TRUE); |
      MausTauschrsc.blkprot : CatEdit.BlockProtect (ownTopWdw); |
      MausTauschrsc.writeblo: QuoteBlock(ownTopWdw, CatGlobal.WithShift(kstate)) |
      MausTauschrsc.infoline: WriteInfoline(ownTopWdw, kstate) |
      MausTauschrsc.findrepl: CatOpts.DoSearch() |
      MausTauschrsc.ttsagain: CatOpts.DoSearchAgain (kstate); |
      MausTauschrsc.brepl:    CatOpts.DoReplace (ownTopWdw) |
      MausTauschrsc.tchflag : IF grin.grinWindowTop (ownTopWdw)
                              THEN
                                actSet := DialActionSet{ChangeMsg, ChangeTree, ChangeTreeDown};
                              ELSE
                                actSet := DialActionSet{ChangeSelected};
                              END;
                              ConfVars.GetConfDefInt (cFlagSelection, v.int, 0);
                              lastAction := DialAction (v.int);
                              ConfVars.GetConfDefInt (cFlagSetBits, v.int, 0);
                              setBits := BITSET (v.int);
                              ConfVars.GetConfDefInt (cFlagClearBits, v.int, 0);
                              clearBits := BITSET (v.int);
                              IF FlagDial(actSet, setBits, clearBits, lastAction) THEN
                                IF lastAction = ChangeMsg THEN
                                  grin.newStatus(ownTopWdw, clearBits, setBits);
                                ELSIF lastAction = ChangeTree THEN
                                  grin.changeTree(ownTopWdw, clearBits, setBits, TRUE);
                                ELSIF lastAction = ChangeTreeDown THEN
                                  grin.changeTree(ownTopWdw, clearBits, setBits, FALSE);
                                ELSIF lastAction = ChangeSelected THEN
                                  IF msgList.listWindowTop (ownTopWdw)
                                  THEN
                                    msgList.listSetFlags (ownTopWdw, setBits, clearBits);
                                  ELSIF treeList.treeWindowTop (ownTopWdw)
                                  THEN
                                    treeList.treeSetFlags (ownTopWdw, setBits, clearBits);
                                  END;
                                END;
                              END; |
      
      (* Nachrichten-Menu *)
      MausTauschrsc.tneue   : ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.readnew); |  
      MausTauschrsc.tunread : ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.readunread); |  
      MausTauschrsc.tlastpos: ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.readpos); |  
      MausTauschrsc.tanfang : ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.readall); |  
      MausTauschrsc.tdatum  : ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.readdate); |  
      MausTauschrsc.tnummer : ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.readnum); |  
      MausTauschrsc.treadmsg: IF BMess THEN
                                ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.stichwor); 
                              ELSE
                                ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.messages);
                              END; |  
      MausTauschrsc.tnewallg: ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.newmess); |  
      MausTauschrsc.tnewpers: ButtonHandler (0, 0, {}, 0, {}, MausTauschrsc.newpers); |  
      MausTauschrsc.tresub  : WiederVorlage.SelectResub(); |
      MausTauschrsc.tsearch : IF grin.grinWindowTop (ownTopWdw)
                              THEN
                                grin.SearchMenu(ownTopWdw) 
                              ELSIF msgList.listWindowTop (ownTopWdw)
                              THEN
                                msgList.listSearch (ownTopWdw);
                              END; |
      MausTauschrsc.tmsagain: grin.DoSearch (ownTopWdw, ~CatGlobal.WithShift (kstate)) |
      MausTauschrsc.tsuchnb : grin.grinNextNotWorked(ownTopWdw, CatGlobal.WithShift(kstate))|
      
      (* Fenstermenu *)
      MausTauschrsc.cyclewin: WdwManager.TopNextWindow () |
      MausTauschrsc.fullwin : WdwManager.FullWindow (ownTopWdw); |
      MausTauschrsc.closeall: grin.grinCloseAll();
                              msgList.listCloseAll();
                              treeList.treeCloseAll();
                              buttonWindowLocked := TRUE;
                              v.bool := WdwManager.CloseAllWindows (FALSE); 
                              buttonWindowLocked := FALSE;
                              |
      MausTauschrsc.tbuttonw: ButtonWindowOpen := DisplayButton(FALSE) |            (* F7 *)
      MausTauschrsc.wstacked: WdwManager.ArrangeWindows (WdwManager.STACKED); |
      MausTauschrsc.wneben  : WdwManager.ArrangeWindows (WdwManager.BYSIDE); |
      MausTauschrsc.wstaffel: WdwManager.ArrangeWindows (WdwManager.OVERLAP); |
      MausTauschrsc.wtiled  : WdwManager.ArrangeWindows (WdwManager.TILED); |
      
      (* Tausch-Menu *)
      MausTauschrsc.makeein: IF UserBLK.security &
                                (mtAlerts.Alert(1, makeInAlt) = 1) OR
                                 ~UserBLK.security
                             THEN
                                v.bool := CreateInfile();
                             END; |
      MausTauschrsc.decode : IF UserBLK.security &
                                (mtAlerts.Alert(1, insOutAlt) = 1) OR
                                ~UserBLK.security
                             THEN
                               DecodeOutfile()
                             END; |
      MausTauschrsc.tterminal: StartTerminal(FALSE) |
      MausTauschrsc.abrufein: CatOpts.DoAbruf() |
      MausTauschrsc.infosein: CatOpts.DoInfos() |
      MausTauschrsc.tcallitk: v.bool := DoITK.SelectCmd() |
      MausTauschrsc.mgetuser: CatOpts2.DoUserSelect() |
      MausTauschrsc.tgrauswa: GruppenAuswahl.DoGroupSelect (groups) |

      (* Optionen-Menu *)
      MausTauschrsc.aoptions: CatOpts.DoOption () | (* allgemeine Einstellungen *) 
      MausTauschrsc.toptions: CatOpts.DoTausch (); | (* Tausch-Einstellungen *)
      MausTauschrsc.aprinter: CatOpts.doPrinter(); |
      MausTauschrsc.oliste  : CatOpts.doList(); |
      MausTauschrsc.akonfig : CatOpts.doConfig(); |
      MausTauschrsc.oiofilt : CatOpts2.doIOFilter(); |
      MausTauschrsc.aformats: CatOpts.doFormat(); |
      MausTauschrsc.ofloskel: CatOpts2.doFloskel(); |
      MausTauschrsc.ogroups : v.bool := ListHelp.SelectGroup (message, v.card, FALSE, TRUE, FALSE, ListHelp.gsmModify); |
      MausTauschrsc.efont   : WdwManager.GetTopWindow (ownTopWdw, hdl);
                              IF hdl > 0
                              THEN
                                font := FontSelect.FontActive (hdl);
                                FontSelect.FontInfo (hdl, font, fInfo);
                                font := fInfo.id;
                                size := fInfo.point;
                                IF grin.grinWindowTop (ownTopWdw)
                                THEN
                                  IF CatGlobal.WithShift (kstate)
                                  THEN
                                    grin.GetAlternativeFont (font, size);
                                    SelectFont(hdl, ownTopWdw, TRUE, font, size, grin.grinSetAlternativeFont);
                                    IF grin.grinWithEffects (ownTopWdw)
                                    THEN
                                      grin.GetWdwFont (ownTopWdw, font, size);
                                      FontSelect.SetFont (hdl, font, size, FALSE, v.bool, v.bool, v.int, v.int); 
                                    END;
                                  ELSE
                                    grin.GetWdwFont (ownTopWdw, font, size);
                                    SelectFont(hdl, ownTopWdw, FALSE, font, size, grin.grinSetFont);
                                    IF ~grin.grinWithEffects (ownTopWdw)
                                    THEN
                                      grin.GetAlternativeFont (font, size);
                                      FontSelect.SetFont (hdl, font, size, FALSE, v.bool, v.bool, v.int, v.int); 
                                    END;
                                  END;
                                ELSIF CatEdit.IsEditTop (ownTopWdw)
                                THEN
                                  SelectFont(hdl, ownTopWdw, FALSE, font, size, CatEdit.SelectEditFont);
                                ELSIF msgList.listWindowTop (ownTopWdw)
                                THEN
                                  SelectFont(hdl, ownTopWdw, FALSE, font, size, msgList.listSetFont);
                                ELSIF MsgWindow.msgWindowTop (ownTopWdw)
                                THEN
                                  SelectFont(hdl, ownTopWdw, FALSE, font, size, MsgWindow.msgSetFont);
                                ELSIF treeList.treeWindowTop (ownTopWdw)
                                THEN
                                  SelectFont(hdl, ownTopWdw, FALSE, font, size, treeList.treeSetFont);
                                END;
                              END;
                              |
      MausTauschrsc.ocolor  : CatOpts.doColor (ownTopWdw); |
      MausTauschrsc.oeditor : CatOpts.doEditor (ownTopWdw); |
      
      MausTauschrsc.opsave  : IF UserBLK.security &
                                 (mtAlerts.Alert(1, saveCnfAlt) = 1) OR
                                 ~UserBLK.security
                              THEN
                                CatUtil.WriteUserBlock();
                              END; |

    ELSE

  END;
  MagicAES.MenuTnormal(menu, title, MagicAES.Set);
END MenuMessageHandler;

(*----------------------------------------------*)

PROCEDURE HandleCommands (arg: ARRAY OF CHAR): BOOLEAN;
VAR z    : CARDINAL;
    o, d : BOOLEAN;
BEGIN
  batchProcess := TRUE;
  o := UserBLK.security; UserBLK.security := FALSE;
  FOR z := 1 TO SmallerCard(MagicStrings.Length(arg), 4) DO
    IF    MagicStrings.Cap(arg[z]) = 'I' THEN v.bool := MakeInFile();
    ELSIF MagicStrings.Cap(arg[z]) = 'T' THEN StartTerminal(TRUE);
    ELSIF MagicStrings.Cap(arg[z]) = 'O' THEN DecodeOutfile();
    ELSIF MagicStrings.Cap(arg[z]) = 'Q' THEN EndOfPrg := TRUE;
    END;
  END;
  UserBLK.security := o;
  batchProcess := FALSE;
  RETURN TRUE
END HandleCommands;

PROCEDURE HandleBatch():BOOLEAN;
VAR arg  : ARRAY[0..126] OF CHAR;
    z    : CARDINAL;
    o, d : BOOLEAN;
    i    : INTEGER;
BEGIN
  IF mtCommand.ParamCount() > 0 THEN
    mtCommand.ParamString(1, arg);
    IF arg[0] # '-' THEN
      mtCommand.ParamString(2, arg);
    END;
    IF arg[0] = '-' THEN
      RETURN HandleCommands (arg);
    END;
  END;
  RETURN FALSE
END HandleBatch;

PROCEDURE dummyProc():BOOLEAN;
  VAR cfgFile : CatTypes.String255;
BEGIN
  v.bool := TellLoadingBox (cInitConfig);

  (* Erstmal zur�cksetzen auf TOS-Domain *)
  v.bool := Mintbind.Pdomain (0) = 0;
  
  (* Pr�fen, ob wir in der Mint-Domain laufen sollen *)
  ConfVars.GetConfDefBool (cMintDomain, v.bool, TRUE);
  IF v.bool
  THEN
    isMintDomain := Mintbind.Pdomain (1) = 0;
  ELSE
    v.bool := Mintbind.Pdomain (0) = 0;
    isMintDomain := FALSE;
  END;

  ReadUserBlock();
  CatGlobal.SetColors();
  IF ConfVars.GetConfigString (cPrtCfg, cfgFile)
  THEN
    v.bool := TellLoadingBox (cInitPrint);
    Printer.LoadCFGFile (cfgFile);
  END;
  v.bool := TellLoadingBox (cInitInfos);
  LoadInfoInf(FALSE, FALSE);
  RETURN InitVDIStandards();
END dummyProc;

PROCEDURE IsOn(item : INTEGER):BOOLEAN;
BEGIN
  RETURN ~(3 IN BITSET(GetState(menu, item)))
END IsOn;

PROCEDURE clickHandler (x, y : INTEGER; Button: BITSET; Clicks: INTEGER; kstate : BITSET);
  VAR wdw   : INTEGER;
      res   : INTEGER;
      popStr: ARRAY [0..79] OF CHAR;
BEGIN
  IF (1 IN Button) & ~(0 IN Button)
  THEN
    WdwManager.ClickInWindow (x, y, wdw);
    IF wdw >= 0
    THEN
      IF CatEdit.IsEditTop (wdw)
       & CatEdit.ClickIsInBlock (wdw, x, y)
       & (Clicks = 1)
      THEN
        IF grin.grinWindowTop (wdw)
        THEN
          popStr := " Kopieren | Filtern...";
          (* Testen, ob Topwindow Editorfenster ist *)
          IF ~grin.grinWindowTop (WdwManager.theTopWindow) 
             & CatEdit.IsEditTop (WdwManager.theTopWindow)
          THEN
            (* Quoten ist auch m”glich *)
            MagicStrings.Append ("| Quoten", popStr);
          END;
          res := mtPopups.PosPopup (x, y, popStr, "");
          CASE res OF
            0: v.bool := CatEdit.EditCopy (wdw); |
            1: ProcessFilter (wdw, FALSE); |
            2: QuoteBlock (WdwManager.theTopWindow, CatGlobal.WithShift (kstate)); |
          ELSE
          END;
        ELSE
          (* Normaler Editor ist Top *)
          popStr := " Einf�gen | Ausschneiden | Kopieren | Filtern... | Sch�tzen";
          res := mtPopups.PosPopup (x, y, popStr, "");
          CASE res OF
            0: CatEdit.EditPaste (wdw); |
            1: v.bool := CatEdit.EditCut (wdw); |
            2: v.bool := CatEdit.EditCopy (wdw); |
            3: ProcessFilter (wdw, FALSE); |
            4: CatEdit.BlockProtect (wdw); |
          ELSE
          END;
        END;
      END;
    END;
  ELSE
    ButtonHandler(x, y, Button, Clicks, kstate, -1);
  END;
END clickHandler;

PROCEDURE keyHandler (scan, char : CHAR; moKState : BITSET): BOOLEAN;
CONST specialScans = CatTypes.charSet{155C,156C,157C,152C,153C,154C,147C,150C,151C,160C,
                 201C,170C,171C,172C,173C,174C,175C,176C,177C,200C};
      cursorScans  = CatTypes.charSet{110C, 113C, 115C, 120C};
      helpScan     = 142C;
  VAR num : INTEGER;
      val : ARRAY [0..511] OF CHAR;
      varName : ARRAY [0..39] OF CHAR;
      done: BOOLEAN;
      topWindow: INTEGER;
BEGIN
  WdwManager.GetOwnTopWindow (topWindow);
  done := FALSE;
  IF ((scan >= 73C) & (scan <= 104C))        (* ohne Shift *)
    OR  ((scan >= 124C) & (scan <= 135C))       (* mit Shift  *)
  THEN
    done := TRUE;
    IF ~mouse THEN
      mtAppl.MouseOn; mouse := TRUE;
    END;
    IF ~(CatGlobal.WithShift (moKState) OR CatGlobal.WithCtrl (moKState) OR CatGlobal.WithAlt (moKState))
    THEN
      CASE scan OF
        (* Funktionstasten, also ButtonHandler aufrufen! *)
        73C : ButtonHandler(0,0,{},0, {}, MausTauschrsc.readnew)|   (* F1 *)
        74C : ButtonHandler(0,0,{},0, {}, MausTauschrsc.readunread)|(* F2 *)
        75C : ButtonHandler(0,0,{},0, {}, MausTauschrsc.readpos)|   (* F3 *)
        76C : ButtonHandler(0,0,{},0, {}, MausTauschrsc.readall)|   (* F4 *)
        77C : ButtonHandler(0,0,{},0, {}, MausTauschrsc.readdate)|  (* F5 *)
        100C : ButtonHandler(0,0,{},0, {}, MausTauschrsc.readnum)|  (* F6 *)
        101C: ButtonWindowOpen := DisplayButton(FALSE)|            (* F7 *)
        102C: IF BMess THEN  
                ButtonHandler(0,0,{},0, {}, MausTauschrsc.stichwor)
              ELSE
                ButtonHandler(0,0,{},0, {}, MausTauschrsc.messages)
              END;|(* F8 *)
        103C: ButtonHandler(0,0,{},0, {}, MausTauschrsc.newmess)| (* F9 *)
        104C: ButtonHandler(0,0,{},0, {}, MausTauschrsc.newpers)  (* F10 *)
      ELSE
        done := FALSE;
      END
    ELSIF ~CatGlobal.WithCtrl (moKState) & CatGlobal.WithShift (moKState) & (scan >= 124C)
    THEN
      IF CatEdit.IsEditTop (topWindow) & (MagicAES.MUTIMER IN lastEvent)
      THEN
        (* mit Shift! *)
        num := INTEGER(ORD(scan)) - 84 + 1;
        Strings.Assign (cShiftFkey, varName, v.bool);
        Strings.Append (StrConv.IntToStr (num,0), varName, v.bool);
        IF ConfVars.GetConfigString (varName, val)
        THEN
          v.bool := CatEdit.PutLine (topWindow, ADR(val), LENGTH (val));
        END;
      END;
    ELSIF CatGlobal.WithCtrl (moKState) & ~CatGlobal.WithShift(moKState) & (scan <= 104C)
    THEN
      IF CatEdit.IsEditTop (topWindow) & (MagicAES.MUTIMER IN lastEvent)
      THEN
        (* mit Control! *)
        num := INTEGER(ORD(scan)) - 59 + 1;
        Strings.Assign (cCtrlFkey, varName, v.bool);
        Strings.Append (StrConv.IntToStr (num,0), varName, v.bool);
        IF ConfVars.GetConfigString (varName, val)
        THEN
          v.bool := CatEdit.PutLine (topWindow, ADR(val), LENGTH (val));
        END;
      END;
    ELSIF mayUseHidden & 
        CatGlobal.WithAlt(moKState) 
    THEN 
      IF (scan = 73C)   (* 73C *)
      THEN
        (* Alt-F1: 
         * Alle folgenden Nachrichten auf Gelesen setzen und zur n„chsten Gruppe 
         *)
         grin.hiddenFeature (topWindow, 0);
      ELSIF (scan = 74C)
      THEN
        (* Alt-F2: 
         * Alle Ungelesenen auf Gelesen setzen und zur n„chsten Gruppe
         *)
         grin.hiddenFeature (topWindow, 1);
      ELSIF (scan = 75C)
      THEN
        (* Alt-F3: 
         * Zur n„chsten Gruppe
         *)
         grin.hiddenFeature (topWindow, 2);
      ELSIF (scan = 76C)
      THEN
        (* Alt-F4: Fenster schliežen
         *)
        v.bool := WdwManager.CloseWindow (topWindow, FALSE);
      ELSE
        done := FALSE;
      END;
    END;
(*
  (* Jetzt die Ctrl-Shift-Shift-!Alt-Kombinationen *)
  ELSIF (scan = 132C) &
        ~CatGlobal.WithAlt(moKState) & CatGlobal.WithCtrl(moKState) &
        (MagicAES.KRSHIFT IN moKState) & (MagicAES.KLSHIFT IN moKState) THEN
    done := TRUE;
    UserBLK.watchBox := ~UserBLK.watchBox;
    v.bool := ConfVars.SetConfigBool (cWatchBox, UserBLK.watchBox);

    event := event - {MagicAES.MUKEYBD}; (* kein Keyboard *)
    (* Shift-Shift-Ctrl F7: watchDog! *)
  ELSIF (scan = 133C) &
        ~CatGlobal.WithAlt(moKState) & CatGlobal.WithCtrl(moKState) &
        (MagicAES.KRSHIFT IN moKState) & (MagicAES.KLSHIFT IN moKState) THEN
    event := event - {MagicAES.MUKEYBD}; (* kein Keyboard *)
    (* Shift-Shift-Ctrl-F8: Neue Ausgeben! *)
    j := mtAlerts.Alert(2, MTE.saveNew);
    IF j = 1 THEN NewOut('','')
    ELSIF j = 2 THEN
      CatGlobal.ApplPath(InPath);
      InSel := '';
      IF CatGlobal.FselGet(InPath, InSel, allWild, 'In welche Datei ausgeben?', FALSE) THEN
        NewOut(InPath, InSel);
      END
    END
  ELSIF (scan = 134C) &
        ~CatGlobal.WithAlt(moKState) & CatGlobal.WithCtrl(moKState) &
        (MagicAES.KRSHIFT IN moKState) & (MagicAES.KLSHIFT IN moKState) THEN
    UserBLK.InfoInSlider := ~UserBLK.InfoInSlider;
    v.bool := ConfVars.SetConfigBool ('InfoInSlider', UserBLK.InfoInSlider);
    
    event := event - {MagicAES.MUKEYBD}; (* kein Keyboard *)
    (* Shift-Shift-Ctrl F9 *)
  ELSIF (scan = 135C) &
        ~CatGlobal.WithAlt(moKState) & CatGlobal.WithCtrl(moKState) &
        (MagicAES.KRSHIFT IN moKState) & (MagicAES.KLSHIFT IN moKState) THEN
    UserBLK.sortGroups := ~UserBLK.sortGroups;
    v.bool := ConfVars.SetConfigBool (cSortGroups, UserBLK.sortGroups);
    event := event - {MagicAES.MUKEYBD}; (* kein Keyboard *)
    (* Shift-Shift-Ctrl F10 *)
  ELSIF CatGlobal.WithAlt(moKState) & (scan IN specialScans) THEN
    (* Handling f�r ALT-0..9 f�r Message-Abruf! *)
    event := event - {MagicAES.MUKEYBD}; (* kein Keyboard *)
    IF    (scan = 160C) OR (scan = 201C) THEN t := 0
    ELSIF (scan = 155C) OR (scan = 170C) THEN t := 1
    ELSIF (scan = 156C) OR (scan = 171C) THEN t := 2
    ELSIF (scan = 157C) OR (scan = 172C) THEN t := 3
    ELSIF (scan = 152C) OR (scan = 173C) THEN t := 4
    ELSIF (scan = 153C) OR (scan = 174C) THEN t := 5
    ELSIF (scan = 154C) OR (scan = 175C) THEN t := 6
    ELSIF (scan = 147C) OR (scan = 176C) THEN t := 7
    ELSIF (scan = 150C) OR (scan = 177C) THEN t := 8
    ELSIF (scan = 151C) OR (scan = 200C) THEN t := 9 END;
*)
(* erstmal nichts.. *)
  ELSIF (scan = helpScan)
  THEN
    doHelp (topWindow, moKState);
  ELSE
    done := FALSE;
  END;
  RETURN done;
END keyHandler;

PROCEDURE OnlyWildcards (name: ARRAY OF CHAR): BOOLEAN;
  VAR i, l : INTEGER;
BEGIN
  l := LENGTH (name);
  i := 0;
  WHILE i < l DO
    IF ~(name[i] IN CatTypes.charSet {'*','?','.'})
    THEN RETURN FALSE
    END;
    INC (i);
  END;
  RETURN TRUE;
END OnlyWildcards;

PROCEDURE msgHandler (pBuf : ADDRESS; kstate : BITSET): BOOLEAN;
  VAR ch, scan : CHAR;
      moKState : BITSET;
      pName, pCmd : CatTypes.Str255Ptr;
      path : CatTypes.pathStrType;
      name : CatTypes.nameStrType;
      suff : CatTypes.extStrType;
      title, 
      item : INTEGER;
      wdw  : INTEGER;
      pBuff: POINTER TO ARRAY [0..15] OF INTEGER;
      done : BOOLEAN;
      evt  : BITSET;
BEGIN
  done := TRUE;
  pBuff := pBuf;
  CASE IsProtokoll(pBuff, kReturn, moKState, pName, pCmd) OF
    rNoproto :
      CASE pBuff^[0] OF
        MagicAES.MNSELECTED : 
            event := event - {MagicAES.MUBUTTON}; (* keine Buttons *)
            MenuMessageHandler(pBuff^[4], pBuff^[3], kstate); |
        MagicAES.APTERM : 
            IF saveAllPositions
            THEN
              EndOfPrg := CatUtil.WriteSavePos (TRUE, TRUE);
            END;
            fastExit := TRUE; 
            EndOfPrg := TRUE; |
        MagicAES.CHEXIT:
            (* Tochterprozež beendet *)
            IF (termPid > 0) & (pBuff^[3] = termPid)
            THEN
              (* Terminalprogramm beendet *)
              termPid := -1;
              IF pBuff^[4] = 0
              THEN
                v.int := 0;
                IF ConfVars.GetConfigInt (cWaitAfterTerm, v.int)
                THEN
                  MagicAES.WindUpdate (MagicAES.ENDUPDATE);
                  MagicAES.EvntTimer (LONGCARD(LONG(v.int)) * 1000L);
                  MagicAES.WindUpdate (MagicAES.BEGUPDATE);
                END;
                (* Nur bei Exitcode 0 *)
                IF UserBLK.DecodeAfterRun & 
                   ((UserBLK.security & 
                    (mtAlerts.Alert (1, "[2][CAT:|Terminalprogramm beendet!|Soll das Outfile jetzt|eingef�gt werden?][[Ja|:[Nein]") = 1))
                    OR ~UserBLK.security)
                THEN
                  DecodeOutfile()
                END;
              END;
              IF ~batchProcess & ~EndOfPrg & termStarted
              THEN
                WiederVorlage.CheckForResub();
                termStarted := FALSE;
              END;
            END; |
        MagicAES.SCCHANGED:
            (* Clipboardinhalt hat sich ge„ndert *)
            Clip.ScrapIsDirty(); |
      ELSE
      END|
    rNone    : done := FALSE; |
    rChar    : SplitWordToByte(kReturn, scan, char);
               lastApId := pBuff^[1];
               
               IF MenuSearch(menu, mtAppl.ApplIdent, moKState, kReturn,
                             MenuMessageHandler, ~mouse) THEN
                 mouse := TRUE;
                 event := event - {MagicAES.MUKEYBD}; (* kein Keyboard *)
               ELSE
                 (* Event-Handler aufrufen mit MU_KEYBD *)
                 evt := {MagicAES.MUKEYBD};
                 done := WdwManager.HandleEvent (evt, pBuff^, {}, moKState,
                                                 char, scan, kReturn, 0, 0, 0);
               END; |
    (* Anderer Tastendruck wird evtl. �bergemangelt.. *)
    rText    : WdwManager.GetOwnTopWindow (wdw);
               IF CatEdit.IsEditTop (wdw) & 
                  ~grin.grinWindowTop (wdw)
               THEN
                 SendAcknowledge (kReturn, CatEdit.PutLine (wdw, pName, (*SYSTEM.*)LENGTH (pName^)));
               ELSE
                 SendAcknowledge (kReturn, FALSE);
               END; |
    rStart   : mtDir.SplitPath(pName^, path, name, suff);
               IF (pCmd # NIL) THEN
                 v.int := StartPrg(path, name, pCmd^, TRUE, TRUE);
                 SendProgstart (v.int # 0);
               ELSE
                 suff := '';
                 v.int := StartPrg(path, name, suff, TRUE, TRUE);
                 SendProgstart (v.int # 0);
               END|
    rOpen    : (* Entweder AV_OPENWIND oder VA_START. Bei VA_START ist pName NIL!,
                * und in pCmd steht eine Kommandozeile. Bei OpenWind steht in pName 
                * der Pfad und in pCmd ein Dateiname.
                *)
               IF pName # NIL
               THEN
                 (* AV_OPENWIND: Editor mit Datei ”ffnen *)
                 IF OnlyWildcards(pCmd^)
                 THEN
                   MagicStrings.Assign (pName^, openPath);
                   MagicStrings.Assign ('', openSel);
                   IF CatGlobal.FselGet(openPath, openSel, allWild, 'Datei laden', FALSE) 
                   THEN
                     OpenEditWindow(openPath, openSel, FALSE, FALSE);
                   END;
                 ELSE
                   OpenEditWindow(pName^, pCmd^, FALSE, FALSE);
                 END;
               ELSE
                 (* VA_START: pCmd enth„lt Kommandozeile *)
                 IF (pCmd # NIL) & (MagicStrings.Length (pCmd^) > 0)
                 THEN
                   (* Jetzt Kommandozeile auswerten: 
                    * entweder ist ein Dateiname enthalten oder sie f„ngt mit 
                    * - an und ist eine Kommandoliste
                    *)
                   IF pCmd^[0] # '-'
                   THEN
                     (* Ist wohl ein Dateiname, also INF laden *)
                     mtDir.SplitPath (pCmd^, CatGlobal.infPath, CatGlobal.infName, name);
                     ReadInfoDatei (FALSE, FALSE);
                   ELSE
                     (* Liste von Befehlen *)
                     v.bool := HandleCommands (pCmd^);
                   END;
                 ELSE 
                   (* Leere Kommandozeile, Fenster toppen *)
                   ButtonWindowOpen := DisplayButton (FALSE);
                 END;
               END;
               |
    rExtCatMsg:(* Erweiterte CAT-Nachricht *)
               CASE kReturn OF
                 CatReadMsgInfo : MsgWindow.msgUpdateInfo (); |
               ELSE
               END; |
  ELSE
    done := FALSE;
  END;
  RETURN done;
END msgHandler;

VAR crash : BOOLEAN;

(* Hier kommt jetzt der Crash-Handler *)
PROCEDURE crashHandler;
  (* Wird automatisch bei Terminierung des Programms aufgerufen *)
BEGIN
  mtAppl.MouseOn();
  v.int := MagicAES.MenuBar(menu, MagicAES.Reset);
  CloseButton(TRUE);
  IF saveAllPositions & crash
  THEN
    v.bool := CatUtil.WriteSavePos (fastExit, TRUE);
  ELSE
    grin.grinCloseAll ();
    msgList.listCloseAll();
    treeList.treeCloseAll();
    v.bool := WdwManager.CloseAllWindows (fastExit);
  END;
  msgList.listFreeAll();
  v.bool := data.WritePos();       (* Positionstabelle zur�ckschreiben *)
  IF UserBLK.autosave THEN CatUtil.WriteUserBlock() END; (* Userinfo schreiben               *)
  IF UserBLK.MakeAtEnd THEN v.bool := MakeInFile() END;
  v.bool := GroupSelect.SaveChangedGroupList();
  MausTauschrsc.RscFree();
  SendTerminate(TRUE);
  IF ~startTerm & minTos14 & ~neoDeskBugFix
  THEN
    v.int := MagicAES.ShelWrite(0,1,0, '', ''); (* Dann den ShelWrite zur�cknehmen *)
  END;
  IF crash THEN Parser.EmergencyClose() END; (* catlog.txt schliežen *)
  ConfVars.CloseConfig ();                   (* catuser.req schliežen, falls offen *)
  MagicAES.WindUpdate(MagicAES.ENDUPDATE);
  mtAppl.ApplTerm(0);
END crashHandler;

PROCEDURE globalKeyHandler (kReturn: INTEGER; char, scan : CHAR; moKState : BITSET): BOOLEAN;
  VAR done : BOOLEAN;
BEGIN
  done := FALSE;
  IF (CatGlobal.WithCtrl (moKState) OR CatGlobal.WithAlt (moKState))
     & MenuSearch(menu, mtAppl.ApplIdent, moKState, kReturn,
                  MenuMessageHandler, ~mouse) THEN
    mouse := TRUE; (* Wird dann in MenuSearch gemacht *)
    RETURN TRUE;
  ELSE
    done := keyHandler (scan, char, moKState);
    IF mouse & ~(CatGlobal.WithCtrl (moKState) OR CatGlobal.WithAlt (moKState)) 
    & ~WdwManager.ModalWindowTop ()
    THEN
      IF dontSwitchOffMouse
      THEN
        dontSwitchOffMouse := FALSE
      ELSE
        mtAppl.MouseOff();
        mouse := FALSE;
      END;
    END;
  END;
  RETURN done;
END globalKeyHandler;

PROCEDURE handleEvents();
  VAR vdi : INTEGER;
      title, 
      item: INTEGER;
BEGIN
  ClearBuffer(event, FALSE, moKState, ORD(scan), char);
  
  (* Tastencodes mit Shift gehen immer zuerst an das Fenster! *)
  v.bool := WdwManager.HandleEvent (event, mess, moButton, moKState, char, scan, kReturn, moX, moY, bReturn);
  
  IF MagicAES.MUM1 IN event THEN
    IF ~mouse THEN
      mtAppl.MouseOn; mouse := TRUE; 
    END;
  END;
  IF MagicAES.MUBUTTON IN event THEN (* Button *)
    clickHandler (moX, moY, moButton, bReturn, moKState);
  END;
  IF ~mouse 
  THEN
    (* Feststellen, ob das Fenster uns geh”rt *)
    WdwManager.GetTopWindow (v.int, vdi);
    IF vdi <= 0
    THEN
      (* Fenster einer anderen Applikation ist oben, Maus anschalten *)
      mtAppl.MouseOn; mouse := TRUE;
    END;
  END;
  ButtonWindowOpen := CatButtons.WinHandle >= 0;
END handleEvents;

PROCEDURE CheckSingleCAT(): BOOLEAN;
  CONST     doubleAlert = '[3][CAT:|CAT oder CatPutz|ist schon gestartet.][[Abbruch]';
  VAR appName : CatTypes.String127;
      i       : INTEGER;
      otherId : INTEGER;
BEGIN
  IF multiTask
  THEN
    IF multiTOS OR (magIx & (magIxVer >= $200))
    THEN
      (* CAT mittels ApplSearch suchen *)
      FOR i := 0 TO 12 DO appName[i] := 0C; END;
      IF MagicAES.ApplSearch (MagicAES.APFIRST, appName, v.int, otherId)
      THEN
        REPEAT 
          Strings.DelTrailingBlanks (appName);
          IF (otherId # mtAppl.ApplIdent) & 
              (Strings.StrEqual(appName, 'CAT') OR
               Strings.StrEqual(appName, 'CATPUTZ'))
          THEN
            MTE.info (doubleAlert);
            (* Tja, leider ein anderes CAT gefunden *)
            RETURN FALSE
          END;
          FOR i := 0 TO 12 DO appName[i] := 0C; END;
        UNTIL ~MagicAES.ApplSearch (MagicAES.APNEXT, appName, v.int, otherId);
      END;
    ELSIF magIx
    THEN
      FOR i := 0 TO MagicAES.AESGlobal.apCount-1 DO
        IF i # mtAppl.ApplIdent
        THEN
          appName[0] := '?';
          appName[1] := 0C;
          appName[3] := 0C;
          appName[2] := CHR(i);
          IF (MagicAES.ApplFind (ADR(appName)) # 0) 
          THEN 
            Strings.DelTrailingBlanks (appName);
            IF Strings.StrEqual ('CAT', appName) OR
               Strings.StrEqual ('CATPUTZ', appName)
            THEN
              MTE.info (doubleAlert);
              RETURN FALSE
            END;
          END;
        END;
      END;
    END;
  END;
  RETURN TRUE;
END CheckSingleCAT;

(*$L-,R-,S-*)
PROCEDURE sigHandler();
BEGIN
  ASSEMBLER
    MOVE.W  #TRUE,fastExit
    MOVE.W  #TRUE,EndOfPrg
  END;
END sigHandler;
(*$L=,R=,S=*)

PROCEDURE installSignalHandler();
BEGIN
  IF MintUtil.IsMiNT()
  OR (magIx & (magIxVer >= $450))
  THEN
    (* Folgende Signale werden abgefangen und ignoriert:
     * SIGHUP, SIGINT, SIGSYS, 
     *)
    v.lbset := Mintbind.Psigblock (MagicSys.lBITSET{Mintbind.SIGHUP, Mintbind.SIGINT, Mintbind.SIGSYS});
    (* Folgende Signale werden mit Programmterminierung befolgt:
     * SIGQUIT, SIGPIPE, SIGTERM, SIGXCPU
     * Dabei ist es mir egal, ob die Installation geklappt hat oder nicht.
     *)
    v.a := Mintbind.Psignal (Mintbind.SIGTERM, ADDRESS (sigHandler));
    v.a := Mintbind.Psignal (Mintbind.SIGQUIT, ADDRESS (sigHandler));
    v.a := Mintbind.Psignal (Mintbind.SIGPIPE, ADDRESS (sigHandler));
    v.a := Mintbind.Psignal (Mintbind.SIGXCPU, ADDRESS (sigHandler));
  END;
END installSignalHandler;

PROCEDURE CheckWithAlt (VAR pressed: BOOLEAN);
  VAR wasPressed: BOOLEAN;
BEGIN
  wasPressed := pressed;
  MagicAES.GrafMkstate(moX, moY, moButton, moKState);
  IF MagicAES.KALT IN moKState THEN pressed := TRUE END;
  IF pressed & ~wasPressed
  THEN
    (* Bimmeln *)
    CatGlobal.Bing (7);
  END;
END CheckWithAlt;

VAR stck: MemArea;
    rHdl: TermCarrier;

(* Noch'n paar Variablen *)
VAR catName,
    catCmd,
    termName,
    params   : ARRAY [0..139] OF CHAR;
    p2, p    : INTEGER;
    configFileDa,
    fromTerm : BOOLEAN;

    vbuff    : ARRAY [0..15] OF INTEGER;
    menuName : ARRAY [0..15] OF CHAR;
    found    : BOOLEAN;
    altKeyPressed   : BOOLEAN;
    cd, ed   : LONGCARD;

BEGIN
  MagicDOS.Fsetdta (ADR(catDTA));
  isMintDomain := Mintbind.Pdomain (1) = 0;
  keyWrite := 0;
  keyRead  := 0;
  termPid  := -1;
  termStarted  := FALSE;
  chPid  := -1;
  filterNumber := 0;
  altKeyPressed := FALSE;
  mtDials.DialConfig (mtDials.UseConfig, FALSE);

  (* Bevor wir jetzt irgendetwas anderes machen, 
   * sorgen wir erstmal daf�r, daž kein zweites CAT gestartet ist
   *)
  MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  IF ~CheckSingleCAT () THEN RETURN END;


  MagicAES.WindUpdate (MagicAES.ENDUPDATE);
  installSignalHandler();
  crash := FALSE;
  null.d1  := 0; null.d2 := 0;
  CatGlobal.infPath[0] := 0C; CatGlobal.infName[0] := 0C;
  ButtonWindowOpen := FALSE;
  CatchProcessTerm (rHdl, crashHandler, stck);

(* Hier kann man sich ein:  mtAppl.ApplInit(); denken *)
(* Es wird neuerdings automatisch ausgef�hrt..        *)

  mtAppl.MouseBusy;

  (* Hier jetzt noch Name von CAT ermitteln *)
  WinDials.SetApplicationName ('CAT');
  CatGlobal.SetAppl ('CAT');
  CatGlobal.GetApplPath (params);
  CatGlobal.ApplName (catName);
  Strings.Insert (params, 0, catName, v.bool);

  (* feststellen, ob wir vom Terminalprogramm aus
   * aufgerufen wurden
   *)
  (* Erste šberpr�fung auf Alternate-Taste *)
  CheckWithAlt (altKeyPressed);
  (* Jetzt CATPOS.INF lesen, falls da *)
  ConfVars.ConfigConfigModule (TRUE);
  (* Jetzt tempor„ren Pfad holen *)
  (* Hier m�ssen wir nachsehen, ob im TMP-Dir ein CATPOS.INF 
   * existiert. Wenn ja, dann nehmen wir das. Wenn nein, dann 
   * versuchen wir es nochmal mit dem Applikationpath
   *)
  found := FALSE;
  IF mtCommand.EnvVar ('TMP', params) & (LENGTH (params) > 0)
  THEN
    IF params[LENGTH(params)-1] # '\'
    THEN
      (* ggf. Backslash anh„ngen *)
      Strings.Append ('\', params, v.bool);
    END;
    Strings.Append (CatUtil.tmpInf, params, v.bool);
    v.lcard := FileSize (params, found);
  END;
  IF ~found 
  THEN
    CatGlobal.ApplPath (params);
    Strings.Append (CatUtil.tmpInf, params, v.bool);
    v.lcard := FileSize (params, found);
  END;
  (* CATPOS.INF lesen *)
  IF ConfVars.ReadConfigFile (params)
  THEN
    configFileDa := TRUE;
    v.bool := MagicDOS.Fdelete (params);
    fromTerm := ConfVars.GetConfigString (cOverlayTerm, TerminalName);
    IF ConfVars.GetConfigString (cLastInfName, lastInfName)
    THEN
      mtDir.SplitPath (lastInfName, CatGlobal.infPath, CatGlobal.infName, menuName);
    END;
  ELSE
    fromTerm := FALSE;
    configFileDa := FALSE;
  END;
  (* Und wieder auf normale Einstellung *)
  ConfVars.ConfigConfigModule (FALSE);
  CatGlobal.ApplPath (params);
  (* Erstmal Aufl”sung testen *)
  IF (mtAppl.MaxWidth DIV mtAppl.CharWidth) < 80
  THEN
    mtAppl.MouseArrow;
    j := mtAlerts.Alert(1, '[3][CAT:|Die gew„hlte Aufl”sung ist|zu gering f�r CAT!][[Ciao]');
    (* wird im crashhandler wieder ausgeschaltet *)
    MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  ELSIF ~MausTauschrsc.RscInit() 
  THEN
    mtAppl.MouseArrow;
    j := mtAlerts.Alert(1, '[3][CAT:|CAT.RSC nicht gefunden!][[Ciao]');
    (* wird im crashhandler wieder ausgeschaltet *)
    MagicAES.WindUpdate (MagicAES.BEGUPDATE);    
  ELSIF InitLoadingBox(cInitInf) &
        ReadInf(CatGlobal.infPath, CatGlobal.infName, fromTerm, TRUE) &
        dummyProc() &
        TellLoadingBox (cInitGroups) &
        GroupSelect.ReadGroupList() &
        TellLoadingBox (cInitData) &
        data.InitDataBase() &
        TellLoadingBox (cInitGrin) &
        grin.grinInit() &
        TellLoadingBox (cInitRsc) &
        InitRsc() & 
        TellLoadingBox (cInitClip) &
        Clip.GetScrap (params)
  THEN
    (* Pr�fen, wie die Alerts aussehen sollen *)
    ConfVars.GetConfDefBool (cWinAlerts, v.bool, FALSE);
    WinDials.AlertsInWindow (v.bool);

    (* Wiedervorlageliste lesen *)
    v.bool := WiederVorlage.ReadResubList();
  
    (* Zweite šberpr�fung auf Alternate-Taste *)
    CheckWithAlt (altKeyPressed);

    (* Menubar bei Windowmanager anmelden *)
    WdwManager.InstallGlobalMenu (menu, msgHandler);

    (* Keyboardhandler bei Windowmanager anmelden *)
    WdwManager.InstallGlobalKeyProc (globalKeyHandler);

    (* F�r die FlagBox *)
    setBits := {}; clearBits := {}; lastAction := ChangeMsg;

(* kann bei den folgenden etwas schieflaufen ?? *)
    v.bool := TellLoadingBox (cInitDials);
    ListHelp.Init(gruppen, adr);
    grinTools.Init(wegen, system);
    CatGlobal.SetColors();
          
    WdwManager.EnableIconify (TRUE);
    WdwManager.SetWindowIcon (MausTauschrsc.TreeAddr^[MausTauschrsc.cat_icon]);

    IF MagicCookie.FindCookie (magicPCCookie, v.lcard) 
    THEN
      ConfVars.GetConfDefBool (cMagicPCKeys, v.bool, TRUE);
      IF v.bool
      THEN
        WdwManager.SetMagicPCKeyTranslation (TRUE);
      END;
    END;

    IF ConfVars.GetConfigBool(cSortNames, v.bool) & v.bool
    THEN
      v.bool := TellLoadingBox (cInitNames);
      data.SortList (data.names);
    END;
    
    (* Feststellen, ob der NeoDeskFix aktiv sein soll *)
    neoDeskBugFix := ConfVars.GetConfigBool (cNeoDeskFix, v.bool) & v.bool;
  
    IF multiTOS OR (magIx & (magIxVer >= $300))
    THEN
      (* MultiTOS *)
      MagicStrings.Assign ('  Cat ', menuName);
      MagicStrings.Append (CatTypes.CatVersion, menuName);
      v.int := MagicAES.MenuRegister (mtAppl.ApplIdent, menuName);
      (* Und auch Bescheid sagen, daž wir AP_TERM verstehen *)
      v.int := MagicAES.ShelWrite (MagicAES.InformAES, INTEGER(BITSET{MagicAES.ApTermBit}), 0, "", "");
    END;

    v.bool := TellLoadingBox (cInitMsgMan);
    MsgWindow.InitMessageManager();
    v.bool := TellLoadingBox (cInitList);
    msgList.InitMsgList();

    ConfVars.GetConfDefBool (cReadMess, BMess, TRUE);
    mtUtils.SetState(desk, MausTauschrsc.stichwor, MagicAES.SELECTED, ~BMess);
    mtUtils.SetState(desk, MausTauschrsc.messages, MagicAES.SELECTED, BMess);
    CheckItem (menu, MausTauschrsc.treadmsg, ~BMess);
    v.bool := TellLoadingBox (cInitButton);
    InitButtonWindow();
    FreeLoadingBox ();
    
    (* Setzen des Zeilenaufbaus f�r die Stichwortliste *)
    (* catCmd wird nicht mehr benutzt, kann ich hier tempor„r benutzen *)
    ConfVars.GetConfDefStr (cPrivateLine, catCmd, CatTypes.cPrivateDefault);
    msgList.SetListLine(catCmd, TRUE);
    ConfVars.GetConfDefStr (cGlobalLine, catCmd, CatTypes.cGlobalDefault);
    msgList.SetListLine(catCmd, FALSE);
    ConfVars.GetConfDefBool (cHiddenFeatures, mayUseHidden, FALSE);
    
    (* Ende Init-Prozeduren *)

    (* crash wird zur�ckgesetzt bei normalem Ende *)
    crash := TRUE;
    
    MagicStrings.Assign (MessagePath, openPath);
    openSel[0] := 0C;

    MagicStrings.Assign(MessagePath, CatGlobal.SavePath);
    CatGlobal.ApplPath (CatGlobal.prgPath);
    
    EndOfPrg := FALSE;

    (* Hier jetzt die XACC-Initialisierung f�r MTOS *)
    ProtoInit();

    WdwManager.HandlePendingEvents();    (* k”nnte auch reichen f�r Watchdog!! *)
    MagicAES.WindUpdate(MagicAES.BEGUPDATE); (* wg. sofort wieder aus.. *)

    ConfVars.GetConfDefBool (cSavePos, saveAllPositions, FALSE);
    v.bool := ConfVars.SetConfigBool (cSavePos, saveAllPositions);

    startTerm := FALSE;
    fastExit := FALSE;   (* Gibt an, ob ohne R�ckfrage beendet werden soll (Aufl”sungswechsel unter MultiTOS) *) 
    
    IF ~HandleBatch() THEN
      startTerm := UserBLK.StartTermAtStart & ~fromTerm;
      (* Dritte und letzte šberpr�fung auf Alternate-Taste *)
      CheckWithAlt (altKeyPressed);
      IF altKeyPressed THEN startTerm := ~startTerm END;
      IF startTerm & ~fromTerm THEN 
        (* wieder l”schen, kann in StartTerminal neu gesetzt 
         * werden f�r Overlaystart! *)
        startTerm := FALSE; 
        StartTerminal(FALSE); 
      ELSE
        (* is' doch schon..? 
         * Ne, ist nicht, kann ja auch fromTerm sein! *)
        startTerm := FALSE; 
      END;

      IF ~EndOfPrg & ((UserBLK.DecodeAtStart &
         (~startTerm OR
           startTerm & ~UserBLK.DecodeAfterRun))
         OR (fromTerm & UserBLK.DecodeAfterRun)) THEN
        DecodeOutfile()
      END;
    ELSE
      IF EndOfPrg & saveAllPositions 
      THEN
        v.bool := CatUtil.WriteSavePos (fastExit, TRUE);
      END;
    END;

    IF ~EndOfPrg THEN
      ButtonWindowOpen := DisplayButton (TRUE);

      IF configFileDa
      THEN
        ConfVars.ConfigConfigModule (TRUE);
  
        (* Alles wieder restaurieren *)
        MsgWindow.msgRestorePos();
        grin.grinRestorePos();
        msgList.listRestorePos();
        CatEdit.EditRestorePos();
        ConfVars.DeleteAllVars();
        ConfVars.ConfigConfigModule (FALSE);
      END;
      WdwManager.HandlePendingEvents();    (* k”nnte auch reichen f�r Watchdog!! *)
      v.bool := mtAESMenus.InitMenuline (menu);
      v.int := MagicAES.MenuBar(menu, MagicAES.Set);    (* show our menubar          *)
  
(* ---------------------------------------------------------------------- *)
      mtAppl.MouseArrow;
      mouse := TRUE;
      WITH mrect DO
        x := 0; y := 0; w := 1; h := 1;
      END;
    END;

    (* Prozedur-Handler in WdwManager installieren *)
    WdwManager.handleNewTop := enableNewTop;
    event := {};

    IF ~batchProcess & ~EndOfPrg & ~termStarted
    THEN
      WiederVorlage.CheckForResub ();
    END;

    WHILE ~EndOfPrg DO

      enableMenuItems (WdwManager.theTopWindow);
      MagicAES.WindUpdate(MagicAES.ENDUPDATE);
      
      mtAppl.MouseState (v.int, mouse);

      IF PendingKey()
      THEN
        event := {MagicAES.MUKEYBD};
        PopKey(moKState, scan, char);
      ELSE
        (* Zuerst mal die Arrays setzen *)
        (* Vielleicht nochmal eigene Array, das bringt vielleicht noch mal _etwas_,
           ist aber auch noch aufwendiger.. *)
        IF mouse THEN
          MagicAES.AESIntIn[0] := INTEGER({MagicAES.MUKEYBD, MagicAES.MUBUTTON, MagicAES.MUMESAG, MagicAES.MUTIMER});
        ELSE
          MagicAES.AESIntIn[0] := INTEGER({MagicAES.MUKEYBD, MagicAES.MUBUTTON, MagicAES.MUM1, MagicAES.MUMESAG, MagicAES.MUTIMER});
        END;
  
        (* Rechte und Linke Maustaste abfragen *)
        (* Geht in jeder TOS-Version und ist nun dokumentiert *)
        MagicAES.AESIntIn[1]  := 259;
        MagicAES.AESIntIn[2]  := INTEGER({1,0});
        MagicAES.AESIntIn[3]  := INTEGER({});
        MagicAES.AESIntIn[4]  := MagicAES.LeaveRect;
        WITH mrect DO
          MagicAES.AESIntIn[5]  := x;
          MagicAES.AESIntIn[6]  := y;
          MagicAES.AESIntIn[7]  := w;
          MagicAES.AESIntIn[8]  := h;
        END;
        (*
        MagicAES.AESIntIn[9]  := 0;
        MagicAES.AESIntIn[10] := 0;
        MagicAES.AESIntIn[11] := 0;
        MagicAES.AESIntIn[12] := 0;
        MagicAES.AESIntIn[13] := 0;
        
        *)
        MagicAES.AESIntIn[14] := 350;   (* ev_mtlocount: 350 ms *)
        MagicAES.AESIntIn[15] := 0;     (* ev_mthicount: 0 *)
        
        MagicAES.AESAddrIn[0] := ADR(mess);
        
        lastEvent := event;
        event := MagicAES.EvntPmulti();
  
        moX := MagicAES.AESIntOut[1];
        moY := MagicAES.AESIntOut[2];
        moButton := MagicSys.CastToBitset(MagicAES.AESIntOut[3]);
        moKState := MagicSys.CastToBitset(MagicAES.AESIntOut[4]);
        kReturn  := MagicAES.AESIntOut[5];
        SplitWordToByte(kReturn, scan, char);
        bReturn  := MagicAES.AESIntOut[6];
  
        WITH mrect DO
          x := moX; y := moY;
        END;
      END;

      MagicAES.WindUpdate(MagicAES.BEGUPDATE);

      IF MagicAES.MUBUTTON IN event THEN (* Button *)
        IF ~mouse THEN
          mtAppl.MouseOn; mouse := TRUE; 
        END;
        IF MagicAES.MouseLeft IN moButton THEN
          (* Nicht warten, wenn man die rechte Taste gedr�ckt hat. *)
          (* Sonst kann man Fenster im Hintergrund nicht mehr korrekt bedienen. *)
          (* Warten auf loslassen oder waitingTime *)
          e := MagicAES.EvntMulti(
                     {MagicAES.MUBUTTON, MagicAES.MUTIMER},
                      0,{1,0},{}, 0,dr, 0, dr, vbuff, UserBLK.waitingTime,0,
                      v.int, v.int, v.bset, v.int, v.bset, v.int, v.char, v.int);
        END;
      END;
      handleEvents();

    END; (* WHILE ~EndOfPrg *)

(* ---------------------------------------------------------------------- *)
    crash := FALSE;
    IF startTerm & ~fastExit
    THEN
      (* Terminalprogramm mittels ShelWrite starten *)
      Strings.Concat (TerminalPath, TerminalName, termName, v.bool);
      
      (* Dateinamen zusammensetzen in altem Konfigbereich *)
      CatUtil.GetPosPath (params);
      Strings.Append (CatUtil.tmpInf, params, v.bool);
      (* Variable setzen und rausschreiben *)
      ConfVars.GetConfDefBool (cSetAppName, v.bool, FALSE);
      ConfVars.ConfigConfigModule (TRUE);
      v.bool := ConfVars.SetConfigBool (cSetAppName, v.bool);
      v.bool := ConfVars.SetConfigString (cOverlayTerm, termName);
      v.bool := ConfVars.SetConfigString (cLastInfName, lastInfName);
      CatUtil.isTmp := TRUE;
      v.bool := ConfVars.WriteConfigFile (params, CatUtil.writeInfo);
      ConfVars.ConfigConfigModule (FALSE);
      
      (* Parameterzeile basteln *)
      params := ' '; (* Platz f�r L„nge! *)
      Strings.Append (TerminalCmd, params, v.bool);
      Strings.Append ('/', params, v.bool);
      Strings.Append (catName, params, v.bool);
      params[0] := CHR(Strings.Length (params)-1);
      (* Und los geht's *)
      v.bool := SetPath (TerminalPath);
      IF TerminalPath[1] = ':' THEN
        MagicStrings.Delete (TerminalPath, 0, 2);
        v.bool := SetPath (TerminalPath);
      END;
      v.int := MagicAES.ShelWrite (1, 1, 0, termName, params);
    END;
  ELSE
    FreeLoadingBox ();
    SendTerminate(TRUE);
    (* Wird im CrashHandler wieder ausgeschaltet *)
    MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  END;
END Cat.
